aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Changelog.md30
-rw-r--r--Gentle_introduction_Inpla.md30
-rw-r--r--README.md2
-rw-r--r--src/id_table.c4
-rw-r--r--src/id_table.h3
-rw-r--r--src/inpla.y91
6 files changed, 141 insertions, 19 deletions
diff --git a/Changelog.md b/Changelog.md
index f6cc0dc..9985118 100644
--- a/Changelog.md
+++ b/Changelog.md
@@ -1,5 +1,35 @@
# Change log
+### v0.9.2 (released on 30 July 2022)
+#### New Features
+* **A built-in agent** `Map`: Map function operation is realised by the following definition:
+
+ ```
+ Map(result, f) >< [] => result~[], Eraser~f;
+ Map(result, f) >< x:xs => Dup(f1,f2)~f,
+ result~w:ws,
+ f1 ~ (w, x), Map(ws, f2)~xs;
+ ```
+ Now, the Map has been implemented as built-in.
+ ```
+ >>> inc(r)><(int i)=>r~i+1;
+ >>> Map(r1, (r, inc(r))) ~ [1,2,3];
+ (22 interactions, 0.00 sec)
+ >>> r1;
+ [2,3,4]
+ >>> Map(r2, (r, Add(r,10))) ~ [1,2,3];
+ (26 interactions, 0.00 sec)
+ >>> r2;
+ [11,12,13]
+ >>> Map(r3, %inc) ~ [1,2,3];
+ (12 interactions, 0.00 sec)
+ >>> r3;
+ [2,3,4]
+ >>>
+ ```
+
+
+
### v0.9.1 (released on 28 July 2022)
#### New Features
* **A built-in agent** `Zip`: It takes two lists and returns a list whose elements are pairs of the given two lists elements such that:
diff --git a/Gentle_introduction_Inpla.md b/Gentle_introduction_Inpla.md
index 0903a6f..e2617d1 100644
--- a/Gentle_introduction_Inpla.md
+++ b/Gentle_introduction_Inpla.md
@@ -688,31 +688,31 @@ it merges two lists into one. Merger agent has two principal ports that can take
```
### Map and reduce functions
-* **Lambda and Application like computation**: We can leave an interaction later by using a couple of Tuple2 agents. For instance, an destructor agent `foo` whose arity is 1 can be abstracted as `(r, foo(r))`, and we can give a constructor `s` later:
+* **Lambda-application-like computation**: We can leave an interaction later by using a couple of Tuple2 agents. For instance, an destructor agent `foo` whose arity is 1 can be abstracted as `(r, foo(r))`, and we can give a constructor `s` later:
```
(r, foo(r)) >< (result, s) -->* foo(result)~s.
// where the following rule has been defined as a built-in:
// (a1,a2) ><> (b1,b2) => a1~b1, a2~b2.
```
- So, the map function can be realised:
+* **Map function operation**: So, the map function operation can be realised by a built-in `Map` agent with the following already defined rules:
```
- map(result, f) >< [] => result~[], Eraser~f;
- map(result, f) >< x:xs => Dup(f1,f2)~f,
+ Map(result, f) >< [] => result~[], Eraser~f;
+ Map(result, f) >< x:xs => Dup(f1,f2)~f,
result~w:ws,
- f1 ~ (w, x), map(ws, f2)~xs;
+ f1 ~ (w, x), Map(ws, f2)~xs;
```
Actually, by using the incrementor `inc` we can add one to each list element:
```
inc(r)><(int i) => r~(i+1);
- map( result, (r,inc(r)) ) ~ [10,20,30]
- --> Dup(f1,f2)~(r,inc(r)), result~w:ws, f1~(w,10), map(ws,f2)~[20,30]
- -->* result~w:ws, (r1,inc(r1))~(w,10), map( ws, (r2,inc(r2)) )~[20,30]
- -->* result~w:ws, inc(w)~10, map( ws, (r2,inc(r2)) )~[20,30]
- --> result~w:ws, w~11, map(ws, (r2,inc(r2)) )~[20,30]
- --> result~11:ws, map(ws, (r2,inc(r2)) )~[20,30]
- -->* result~11:21:ws, map(ws, (r3,inc(r3)) )~[30]
- -->* result~11:21:31:ws, map(ws, (r4,inc(r4)) )~[]
+ Map( result, (r,inc(r)) ) ~ [10,20,30]
+ --> Dup(f1,f2)~(r,inc(r)), result~w:ws, f1~(w,10), Map(ws,f2)~[20,30]
+ -->* result~w:ws, (r1,inc(r1))~(w,10), Map( ws, (r2,inc(r2)) )~[20,30]
+ -->* result~w:ws, inc(w)~10, Map( ws, (r2,inc(r2)) )~[20,30]
+ --> result~w:ws, w~11, Map(ws, (r2,inc(r2)) )~[20,30]
+ --> result~11:ws, Map(ws, (r2,inc(r2)) )~[20,30]
+ -->* result~11:21:ws, Map(ws, (r3,inc(r3)) )~[30]
+ -->* result~11:21:31:ws, Map(ws, (r4,inc(r4)) )~[]
-->* result~[11,21,31];
```
The Tuple2 agent seems a little complicated, so we prepare an abbreviation `%`. In the following, `foo1`, `foo2`, `foo3`, ... are any agents whose arity is 1, 2, 3, ..., respectively.
@@ -731,14 +731,14 @@ it merges two lists into one. Merger agent has two principal ports that can take
```
This is quite useful for the map application. The `inc` application is written simply as follows:
```
- >>> map(result, %inc) ~ [1,2,3];
+ >>> Map(result, %inc) ~ [1,2,3];
>>> result;
[2,3,4]
>>>
```
Wonderful!
- The same as the map operation, we can define foldr and foldl as follows (Do not worry if it looks complicated. It is OK if we can just use these!):
+* **Reduce function operation**: The same as the map operation, we can define foldr and foldl as follows (Do not worry if it looks complicated. It is OK if we can just use these!):
```
// --------------------------------------------------------------------
// foldr f v [x0, x1, ..., xn] = f(x0, f(x1, ... f(xn-1, f(xn, v))...))
diff --git a/README.md b/README.md
index 942d41a..fde0cd6 100644
--- a/README.md
+++ b/README.md
@@ -6,7 +6,7 @@
Inpla is a multi-threaded parallel interpreter of interaction nets. Once you write programs for sequential execution, it works also in multi-threaded parallel execution. Each thread is managed on each CPU-core with POSIX-thread library.
-* The current version is 0.9.1, released on **28 July 2022**. (See [Changelog.md](Changelog.md) for details.)
+* The current version is 0.9.2, released on **30 July 2022**. (See [Changelog.md](Changelog.md) for details.)
* The below graph shows speed-up ratio to threads numbers for programs in the following benchmark table.
![speedup-ratio](pic/benchmark_reuse_v0.8.2-2.png)
diff --git a/src/id_table.c b/src/id_table.c
index 2ad96ad..fc22bb1 100644
--- a/src/id_table.c
+++ b/src/id_table.c
@@ -54,6 +54,7 @@ void IdTable_init() {
IdTable[ID_MOD].aux.arity = 2;
IdTable[ID_MOD2].aux.arity = 2;
IdTable[ID_PERCENT].aux.arity = 1;
+ IdTable[ID_MAP].aux.arity = 2;
IdTable[ID_ERASER].aux.arity = 0;
IdTable[ID_DUP].aux.arity = 2;
@@ -86,6 +87,7 @@ void IdTable_init() {
IdTable[ID_MOD].name = "Mod";
IdTable[ID_MOD2].name = "_Mod";
IdTable[ID_PERCENT].name = "%";
+ IdTable[ID_MAP].name = "Map";
IdTable[ID_ERASER].name = "Eraser";
IdTable[ID_DUP].name = "Dup";
@@ -117,6 +119,8 @@ int IdTable_getid_builtin_funcAgent(Ast *agent) {
id = ID_APPEND;
} else if (strcmp((char *)agent->left->sym, "Zip") == 0) {
id = ID_ZIP;
+ } else if (strcmp((char *)agent->left->sym, "Map") == 0) {
+ id = ID_MAP;
} else if (strcmp((char *)agent->left->sym, "Int") == 0) {
id = ID_INTAGENT;
} else if (strcmp((char *)agent->left->sym, "Merger") == 0) {
diff --git a/src/id_table.h b/src/id_table.h
index 7ee04bc..c486975 100644
--- a/src/id_table.h
+++ b/src/id_table.h
@@ -51,7 +51,8 @@
#define ID_MOD 28
#define ID_MOD2 29
#define ID_PERCENT 30
-#define END_ID_OF_BUILTIN_OP_AGENT 30
+#define ID_MAP 31
+#define END_ID_OF_BUILTIN_OP_AGENT 31
// ID_ERASER and ID_DUP was put as 254, 255
// because these IDs are wanted larger like ID_DUP > any_agent.id
diff --git a/src/inpla.y b/src/inpla.y
index 182bed7..6053ff1 100644
--- a/src/inpla.y
+++ b/src/inpla.y
@@ -22,8 +22,8 @@
// ----------------------------------------------
-#define VERSION "0.9.1"
-#define BUILT_DATE "28 July 2022"
+#define VERSION "0.9.2"
+#define BUILT_DATE "30 July 2022"
// ------------------------------------------------------------------
@@ -9635,6 +9635,93 @@ loop_agent_a1_a2_this_order:
break; // end ID_ZIPC
+ case ID_MAP:
+ switch (BASIC(a2)->id) {
+ case ID_NIL:
+ {
+ // Map(result, f) >< [] => result~[], Eraser~f;
+ COUNTUP_INTERACTION(vm);
+
+ VALUE a1p0 = AGENT(a1)->port[0];
+ VALUE a1p1 = AGENT(a1)->port[1];
+
+ // Eraser
+ BASIC(a1)->id = ID_ERASER;
+ PUSH(vm, a1, a1p1);
+
+ a1=a1p0;
+ goto loop;
+ }
+
+ case ID_CONS:
+ {
+ COUNTUP_INTERACTION(vm);
+
+ VALUE a1p0 = AGENT(a1)->port[0];
+ VALUE a1p1 = AGENT(a1)->port[1];
+
+ VALUE a2p0 = AGENT(a2)->port[0];
+ VALUE a2p1 = AGENT(a2)->port[1];
+ VALUE w = make_Name(vm);
+ VALUE ws = make_Name(vm);
+
+ VALUE pair = make_Agent(vm, ID_TUPLE2);
+
+ AGENT(a2)->port[0] = w;
+ AGENT(a2)->port[1] = ws;
+ PUSH(vm, a1p0, a2);
+
+ /*
+ if ((IS_NAMEID(BASIC(a1p1)->id))
+ && (NAME(a1p1)->port != NULL)) {
+ VALUE a1p1_agent = NAME(a1p1)->port;
+ free_Name(a1p1);
+ AGENT(a1)->port[1] = a1p1_agent;
+ }
+ */
+
+ if (BASIC(a1p1)->id == ID_PERCENT) {
+ // special case
+ //Map(result, %f) >< x:xs =>
+ // result~w:ws,
+ // %f ~ (w, x), Map(ws, %f)~xs;
+
+ AGENT(pair)->port[0] = w;
+ AGENT(pair)->port[1] = a2p0;
+ VALUE new_percent = make_Agent(vm, ID_PERCENT);
+ AGENT(new_percent)->port[0] = AGENT(a1p1)->port[0];
+ PUSH(vm, new_percent, pair);
+
+ AGENT(a1)->port[0] = ws;
+ a2 = a2p1;
+ goto loop;
+ }
+
+ // Map(result, f) >< x:xs => Dup(f1,f2)~f,
+ // result~w:ws,
+ // f1 ~ (w, x), map(ws, f2)~xs;
+
+ VALUE dup = make_Agent(vm, ID_DUP);
+ VALUE f1 = make_Name(vm);
+ VALUE f2 = make_Name(vm);
+ AGENT(dup)->port[0] = f1;
+ AGENT(dup)->port[1] = f2;
+ PUSH(vm, dup, a1p1);
+
+ AGENT(pair)->port[0] = w;
+ AGENT(pair)->port[1] = a2p0;
+ PUSH(vm, f1, pair);
+
+ AGENT(a1)->port[0] = ws;
+ AGENT(a1)->port[1] = f2;
+ a2 = a2p1;
+ goto loop;
+
+ }
+ }
+
+ break; // end ID_MAP
+
case ID_MERGER:
switch (BASIC(a2)->id) {