Differences From Artifact [6629940451babbd3]:
- File
readme.txt
- 2010-11-20 16:35:14 - part of checkin [3464a035ec] on branch trunk - source code cleanup (user: kinaba) [annotate]
To Artifact [adcd1590f6f5bc80]:
- File
readme.txt
- 2010-11-21 09:53:17 - part of checkin [435fa085ec] on branch trunk - refactored predefined layer names, and filled readme.txt. (user: kinaba) [annotate]
64 64 | ("var"|"let"|"def"|LAYER) ID "=" E (";"|"in") E
65 65 | ("var"|"let"|"def"|LAYER) ID "(" PARAMS ")" "{" E "}" (";"|"in") E
66 66 | ("var"|"let"|"def"|LAYER) ID "=" E
67 67 | ("var"|"let"|"def"|LAYER) ID "(" PARAMS ")" "{" E "}"
68 68 // literal
69 69 | INTEGER
70 70 | STRING
71 - | "{" ENTRYS "}"
72 - | "fun" "(" PARAMS ")" "{" E "}"
71 + | "{" ENTRYS "}" // table
72 + | "fun" "(" PARAMS ")" "{" E "}" // anonymous function
73 73 // function call
74 74 | E "(" ARGS")"
75 75 where ARGS ::= E "," ... "," E
76 76 PARAMS ::= ID LAYER* "," ... "," ID LAYER*
77 77 ENTRYS ::= ID ":" E "," ... "," ID ":" E
78 78 ID ::= 'a-zA-Z0-9_...'+
79 79 LAYER ::= "@" ID
80 80 // operators
81 81 | "(" E ")"
82 - | E "." ID
83 - | E ".?" ID
82 + | E "." ID // table field access
83 + | E ".?" ID // table field existence check
84 + | E "{" ENTRYS "}" // table extend (pure functionally)
84 85 | E BINOP E
85 86 | "if" "(" E ")" "{" E "}"
86 87 | "if" "(" E ")" "{" E "}" "else "{" E "}"
87 88 // layered exec
88 89 | LAYER "(" E ")"
89 90
90 91 The following are actually rewritten to function calls:
91 92
92 93 - if (E) then{E} else{E} ==> if( E, fun(){E}, fun(){E} )
93 94 - E BINOP E ==> BINOP(E, E)
94 95 - E.ID ==> . (E, ID)
95 96 - E.?ID ==> .?(E, ID)
96 97 - {} ==> {}()
97 - - {ID:E, ...} ==> .=({...}, ID, E)
98 + - { ENTRIES } ==> {}{ ENTRIES }
99 + - E {ID:E, ...} ==> (.=(E, ID, E)) { ... }
98 100
99 101 Several styles of variable declaration can be used:
100 102
101 103 - fun(x){ fun(y){x} } # K-combinator
102 104 - fun(x){ let f = fun(y){x} in f } # let-in style
103 105 - fun(x){ var f = fun(y){x}; f } # var-; style
104 106 - fun(x){ def f = fun(y){x} in f } # you can use any combination of (let|var|def)-(;|in)
................................................................................
125 127 - tables: {car: 1, cdr: {car: 2, cdr: {}}}
126 128 - functions: fun(x){x+1}
127 129 as primitive datatypes. Functions capture lexical closures.
128 130 It is almost 'pure' (except the primitve function "print" and some
129 131 trick inside scoping mechanisms).
130 132
131 133
132 -<<Layer>>
134 +<<Layers :: Overview>>
135 +
136 + Polemy's runtime environment has many "layer"s.
137 + Usual execution run in the @value layer.
138 +
139 + >> 1 + 2
140 + 3
141 + >> @value( 1 + 2 )
142 + 3
143 +
144 + Here you can see that @LayerName( Expression ) executes the inner Expression in
145 + the @LayerName layer. Other than @value, one other predefined layer exists: @macro.
146 +
147 + >> @macro( 1+2 )
148 + {pos@value:{lineno@value:3, column@value:9, filename@value:<REPL>},
149 + is@value:app,
150 + arg@value:{car@value:{pos@value:{lineno@value:3, column@value:9, filename@value:<REPL>},
151 + is@value:int,
152 + data@value:1},
153 + cdr@value:{
154 + car@value:{pos@value:{lineno@value:3, column@value:11, filename@value:<REPL>},
155 + is@value:int,
156 + data@value:2},
157 + cdr@value:{}}},
158 + fun@value:{pos@value:{lineno@value:3, column@value:10, filename@value:<REPL>},
159 + is@value:var,
160 + name@value:+}}
161 +
162 + (Sorry, this pretty printing is not available on the actual interpreter...)
163 + This evaluates the expression 1+2 in the @macro layer. In this layer, the meaning of
164 + the program is its abstract syntax tree.
165 +
166 + You can interleave layers.
167 + The root node of the abstract syntax tree is function "app"lication.
168 +
169 + >> @value(@macro( 1+2 ).is)
170 + app
171 +
172 +
173 +
174 +<<Layers :: Defining a new layer>>
175 +
176 + To define a new layer, you should first tell how to "lift" existing values two the new layer.
177 + Let us define the "@type" layer, where the meaning of programs is their static type.
178 +
179 + >> @@type = fun(x) {
180 + >> if( _isint(x) ) { "int" } else {
181 + >> if( _isfun(x) ) { x } else { "unknown" } }
182 + >> }
183 + (Note: polemy REPL may warn some exception here but please ignore)
184 +
185 + For simplicity, I here deal only with integers.
186 + _isint is a primitive function of Polemy that checks the dynamic type of a value.
187 + For function, leaving it untouched works well for almost all layers.
188 +
189 + >> @type( 1 )
190 + int
191 + >> @type( 2 )
192 + int
193 + >> @type( "foo" )
194 + unknown
195 +
196 + Fine! Let's try to type 1+2.
197 +
198 + >> @type( 1 + 2 )
199 + ...\value.d(119): [<REPL>:6:8] only @value layer can call native function
200 +
201 + Note that the behavior of this program is
202 + - run 1+2 in the @type layer
203 + and NOT
204 + - run 1+2 in @value and obtain 3 and run 3 in the @type.
205 + The problem is, the variable "+" is defined only in the @value layer.
206 + To carry out computation in the @type layer. We need to define it also
207 + in the @type layer.
208 +
209 + To define some variable in a specific layer, use @LayerName in place of
210 + (let|var|def)s.
211 +
212 + >> let x = 2
213 + >> @value x = 2
214 + >> @type x = "int"
215 + >> @hoge x = "fuga"
216 +
217 + For "+", do it like this.
218 +
219 + >> @type "+" = fun(x,y) {@value(
220 + >> if( @type(x)=="int" && @type(y)=="int" ) { "int" } else { "typeerror" }
221 + >> )}
222 + polemy.value.native!(IntValue,IntValue,IntValue).native.__anonclass24
223 +
224 + It is just computing the return type from the input type.
225 + Not here that the intended "meaning" of if-then-else is the runtime-branching,
226 + and the meaning of "==" is the value-comparison. These are the @value layer
227 + behavior. So we have defined the function body inside @value layer.
228 + But when we refer the variables x and y, we need its @type layer meaning.
229 + Hence we use @type() there.
230 +
231 + Now we get it.
232 +
233 + >> @type( 1 + 2 )
234 + int
235 +
236 + Well, but do we have to define the @type layer meaning for every variables???
237 + No. After you defined @type "+", you'll automatically get the following:
238 +
239 + >> def double(x) { x + x }
240 + (function:17e4740:1789720)
241 +
242 + >> @type( double(123) )
243 + int
244 +
245 + Every user-defined functions are automatically "lift"ed to the appropriate layer.
246 + Only primitive functions like "+" requires @yourNewLayer annotation.
247 +
248 +
249 +
250 +<<Layers :: neutral-layer>>
251 +
252 + let|var|def is to define a variable in the "current" layer.
253 + Not necessary to the @value layer.
254 +
255 + >> @value( let x = 1 in @value(x) )
256 + 1
257 +
258 + >> @macro( let x = 1 in @value(x) )
259 + polemy.failure.RuntimeException: [<REPL>:14:29] variable x not found
260 +
261 + >> @macro( let x = 1 in @macro(x) )
262 + {pos@value:{lineno@value:15, ...
263 +
264 +
265 +
266 +<<Layers :: Layered-Parameters>>
267 +
268 + >> def foo(x @macro @value) { {fst: x, snd: @macro(x)} }
269 + (function:1730360:1789720)
270 +
271 + If you annotate function parameters by @LayerNames, when you invoke the function...
272 +
273 + >> foo(1+2)
274 + {snd@value: {pos@value:{lineno@value:17, column@value:5, filename@value:<REPL>},
275 + is@value:app, arg@value:{...
276 + /fst@value:3
277 + /}
278 +
279 + its corresponding arguments are evaluated in the layer and passed to it.
280 + If you specify multiple layers, the argument expression is run multiple times.
281 + If you do not specify any layer for a parameter, it works in the neutral layer.
282 +
283 +
284 +
285 +<<@macro layer>>
286 +
287 + When function is invoked, it first run in the @macro layer, and after that,
288 + it run in the neutral layer. Here is an example.
289 +
290 + >> @macro twice(x) { x; x }
291 + >> def f() { twice(print("Hello")); 999 }
292 + (function:173b6a0:1789720)
293 + >> f()
294 + Hello
295 + Hello
296 + 999
297 +
298 + When the interpreter evaluates f(), it first executes
299 + "twice(print("Hello")); 999"
300 + in the @macro layer. Basically what it does is to just construct its syntax tree.
301 + But, since we have defined the "twice" function in the @macro layer, it is
302 + execute as a function. Resulting syntax tree is
303 + "print("Hello"); print("Hello"); 999"
304 + and this is executed on the neutral (in this example, @value) layer.
305 + This is the reason why you see two "Hello"s.
306 +
307 +
308 +
309 + [[limitations]]
310 +
311 + This @macro layer is a very primitive one, and not a perfect macro language.
312 + Two major limitations are seen in the following "it" example.
313 +
314 + >> @macro LetItBe(x, y) { let it = x in y };
315 +
316 + The variable name is not hygenic, and so without any effort, the syntax tree "y"
317 + can access the outer variable "it".
318 +
319 + >> def foo() { LetItBe( 1+2+3, it*it ) }
320 + >> foo()
321 + 36
322 +
323 + Of course, this is not just a limitation; it can sometimes allow us to write
324 + many interesting macros.
325 +
326 + The other problem is that the macro expansion is only done at function startup.
327 + So
328 +
329 + >> LetItBe( 1+2+3, it*it )
330 + ...\value.d(173): [<REPL>:24:1] variable LetItBe is not set in layer @value
331 +
332 + you cannot directly use the macro in the same scope as the definition.
333 + You need to wrap it up in a function (like the foo() in the above example).
334 +
335 +
336 +
337 + [[quote and unquote]]
338 +
339 + Here is more involved example of code genration.
340 + From "x", it generates "x*x*x*x*x*x*x*x*x*x".
341 +
342 + @macro pow10(x) {
343 + @value(
344 + def pow(x, n) {
345 + if( n == 1 ) { x }
346 + else {
347 + @macro( @value(x) * @value(pow(x,n-1)) )
348 + }
349 + }
350 + in
351 + pow(@macro(x),10)
352 + )
353 + };
133 354
134 - to be written
355 + Here, x is a syntax tree but n is an actual integer. If you read carefully,
356 + you should get what is going on. Basically, @macro can be considered like
357 + quasiquoting and @value to be an escape from it.