+ let x = E in E
+ var x = E in E
+ def x = E in E
+ let x = E ; E
+ var x = E ; E
+ def x = E ; E
+
+
+以上のどれも同じ意味なので、なんとなく関数型っぽく書きたい気分の日は let in を、
+手続き型っぽく書きたい気分の日は var ; を使うとよいでしょう。
+
+
+関数を宣言するときは、fun や λ を省略できます。
+以下の書き換えが行われます。
+
+
+ def f( ARGS ) { E }; E ⇒ def f = fun(ARGS){E}; E
+
+
+他に、もっと手続き型っぽくための書き換え色々
+
+
+ fun () { E; E; E } ⇒ fun () { let _ = E in let _ = E in E }
+ fun () { var x = 100 } ⇒ fun () { var x = 100; x }
+ fun () { var x = 100; } ⇒ fun () { var x = 100; x }
+ fun () { } ⇒ fun () { "(empty function body)" }
+
+
+中身が空の関数に何を返させるかは適当です。今はとりあえず適当に文字列返してます。
+
+
+
+
+
+
+変数のスコープ規則
+
+
+
+
+
+
+基本的には、let によって常識的な感じに変数のスコープがネストします。
+
+
+ let x=21 in let x=x+x in x # 42
+
+
+一方で、"let rec" のような特別な構文はありませんが、
+
+
+ let f = fun(x) { if(x==0){1}else{x*f(x-1)} } in f(10) # 3628800
+
+[Layers :: Overview]
+
+ Polemy's runtime environment has many "layer"s.
+ Usual execution run in the @value layer.
+
+ >> 1 + 2
+ 3
+ >> @value( 1 + 2 )
+ 3
+
+ Here you can see that @LayerName( Expression ) executes the inner Expression in
+ the @LayerName layer. Other than @value, one other predefined layer exists: @macro.
+
+ >> @macro( 1+2 )
+ {pos@value:{lineno@value:3, column@value:9, filename@value:},
+ is@value:app,
+ args@value:{car@value:{pos@value:{lineno@value:3, column@value:9, filename@value:},
+ is@value:int,
+ data@value:1},
+ cdr@value:{
+ car@value:{pos@value:{lineno@value:3, column@value:11, filename@value:},
+ is@value:int,
+ data@value:2},
+ cdr@value:{}}},
+ fun@value:{pos@value:{lineno@value:3, column@value:10, filename@value:},
+ is@value:var,
+ name@value:+}}
+
+ (Sorry, this pretty printing is not available on the actual interpreter...)
+ This evaluates the expression 1+2 in the @macro layer. In this layer, the meaning of
+ the program is its abstract syntax tree.
+
+ You can interleave layers.
+ The root node of the abstract syntax tree is function "app"lication.
+
+ >> @value(@macro( 1+2 ).is)
+ app
+
+
+
+[Layers :: Defining a new layer]
+
+ To define a new layer, you should first tell how to "lift" existing values two the new layer.
+ Let us define the "@type" layer, where the meaning of programs is their static type.
+
+ >> @@type = fun(x) {
+ >> if( _isint(x) ) { "int" } else {
+ >> if( _isfun(x) ) { x } else { "unknown" } }
+ >> }
+ (Note: polemy REPL may warn some exception here but please ignore)
+
+ For simplicity, I here deal only with integers.
+ _isint is a primitive function of Polemy that checks the dynamic type of a value.
+ For function, leaving it untouched works well for almost all layers.
+
+ >> @type( 1 )
+ int
+ >> @type( 2 )
+ int
+ >> @type( "foo" )
+ unknown
+
+ Fine! Let's try to type 1+2.
+
+ >> @type( 1 + 2 )
+ ...\value.d(119): [:6:8] only @value layer can call native function
+
+ Note that the behavior of this program is
+ - run 1+2 in the @type layer
+ and NOT
+ - run 1+2 in @value and obtain 3 and run 3 in the @type.
+ The problem is, the variable "+" is defined only in the @value layer.
+ To carry out computation in the @type layer. We need to define it also
+ in the @type layer.
+
+ To define some variable in a specific layer, use @LayerName in place of
+ (let|var|def)s.
+
+ >> let x = 2
+ >> @value x = 2
+ >> @type x = "int"
+ >> @hoge x = "fuga"
+
+ For "+", do it like this.
+
+ >> @type "+" = fun(x,y) {@value(
+ >> if( @type(x)=="int" && @type(y)=="int" ) { "int" } else { "typeerror" }
+ >> )}
+ polemy.value.native!(IntValue,IntValue,IntValue).native.__anonclass24
+
+ It is just computing the return type from the input type.
+ Not here that the intended "meaning" of if-then-else is the runtime-branching,
+ and the meaning of "==" is the value-comparison. These are the @value layer
+ behavior. So we have defined the function body inside @value layer.
+ But when we refer the variables x and y, we need its @type layer meaning.
+ Hence we use @type() there.
+
+ Now we get it.
+
+ >> @type( 1 + 2 )
+ int
+
+ Well, but do we have to define the @type layer meaning for every variables???
+ No. After you defined @type "+", you'll automatically get the following:
+
+ >> def double(x) { x + x }
+ (function:17e4740:1789720)
+
+ >> @type( double(123) )
+ int
+
+ Every user-defined functions are automatically "lift"ed to the appropriate layer.
+ Only primitive functions like "+" requires @yourNewLayer annotation.
+
+
+
+[Layers :: neutral-layer]
+
+ let|var|def is to define a variable in the "current" layer.
+ Not necessary to the @value layer.
+
+ >> @value( let x = 1 in @value(x) )
+ 1
+
+ >> @macro( let x = 1 in @value(x) )
+ polemy.failure.RuntimeException: [:14:29] variable x not found
+
+ >> @macro( let x = 1 in @macro(x) )
+ {pos@value:{lineno@value:15, ...
+
+
+
+[Layers :: Layered-Parameters]
+
+ >> def foo(x @macro @value) { {fst: x, snd: @macro(x)} }
+ (function:1730360:1789720)
+
+ If you annotate function parameters by @LayerNames, when you invoke the function...
+
+ >> foo(1+2)
+ {snd@value: {pos@value:{lineno@value:17, column@value:5, filename@value:},
+ is@value:app, arg@value:{...
+ /fst@value:3
+ /}
+
+ its corresponding arguments are evaluated in the layer and passed to it.
+ If you specify multiple layers, the argument expression is run multiple times.
+ If you do not specify any layer for a parameter, it works in the neutral layer.
+
+ When function is invoked, it first run in the @macro layer, and after that,
+ it run in the neutral layer. Here is an example.
+
+ >> @macro twice(x) { x; x }
+ >> def f() { twice(print("Hello")); 999 }
+ (function:173b6a0:1789720)
+ >> f()
+ Hello
+ Hello
+ 999
+
+ When the interpreter evaluates f(), it first executes
+ "twice(print("Hello")); 999"
+ in the @macro layer. Basically what it does is to just construct its syntax tree.
+ But, since we have defined the "twice" function in the @macro layer, it is
+ execute as a function. Resulting syntax tree is
+ "print("Hello"); print("Hello"); 999"
+ and this is executed on the neutral (in this example, @value) layer.
+ This is the reason why you see two "Hello"s.
+
+ [[quote and unquote]]
+
+ Here is more involved example of code genration.
+ From "x", it generates "x*x*x*x*x*x*x*x*x*x".
+
+ @macro pow10(x) {
+ @value(
+ def pow(x, n) {
+ if( n == 1 ) { x }
+ else {
+ @macro( @value(x) * @value(pow(x,n-1)) )
+ }
+ }
+ in
+ pow(@macro(x),10)
+ )
+ };
+
+ Here, x is a syntax tree but n is an actual integer. If you read carefully,
+ you should get what is going on. Basically, @macro can be considered like
+ quasiquoting and @value to be an escape from it.
+
+
+
+
+
+微妙な挙動
+
+
+
+
+
+
+ (rawmacro) レイヤの話
+
+ [[limitations]]
+
+ This @macro layer is a very primitive one, and not a perfect macro language.
+ Two major limitations are seen in the following "it" example.
+
+ >> @macro LetItBe(x, y) { let it = x in y };
+
+ The variable name is not hygenic, and so without any effort, the syntax tree "y"
+ can access the outer variable "it".
+
+ >> def foo() { LetItBe( 1+2+3, it*it ) }
+ >> foo()
+ 36
+
+ Of course, this is not just a limitation; it can sometimes allow us to write
+ many interesting macros.
+
+ The other problem is that the macro expansion is only done at function startup.
+ So
+
+ >> LetItBe( 1+2+3, it*it )
+ ...\value.d(173): [:24:1] variable LetItBe is not set in layer @value
+
+ you cannot directly use the macro in the same scope as the definition.
+ You need to wrap it up in a function (like the foo() in the above example).
+
Advance args[] to point the argument list fed to the script.
+ Returns the name of the source file to run, or returns "" if
+ no filename was given. Also, returns to libs[] the list of
+ library source to load.
+
+TODO:
+use std.getopt
+
+
+
+
+
void
+main
+
+
+(string[] args);
+
+
+
+
+
Entry point.
+
+
+
+
+
+
+
+
+ Page was generated with
+
+ on Wed Nov 24 19:09:32 2010
+
+
-NOTE: Theres no "let rec" syntax, but still recursive definition works
- def f(x) { if(x==0){1}else{x*f(x-1)} } in f(10) #=> 3628800
- yet still the code below also works
- def x=21 in def x=x+x in x #=> 42.
- The internal scoping mechanism is a little tricky (this is for coping with
- the "layer" feature explained below), but I hope that it works as everyone
- expects in most cases, as long as you don't use the same-name-variables heavily :).
+基本的には、let によって常識的な感じに変数のスコープがネストします。
+
+
+ let x=21 in let x=x+x in x $(D_COMMENT # 42)
+
+
+一方で、"let rec" のような特別な構文はありませんが、
+
+
+ let f = fun(x) { if(x==0){1}else{x*f(x-1)} } in f(10) $(D_COMMENT # 3628800)
+
+ let x = 1 in
+ let f = fun() {x} in
+ let x = 2 in
+ f() $(D_COMMENT # 2!!)
+
+
+let-in を縦にチェインしたときだけ、同名変数を破壊的に上書きします
+(再帰関数の定義が"うまく"いっているのはこの上書きのためです)。
+なんでこんなことになっているかというと、
+後で説明する「レイヤ」を使ったときに
+let foo = ... in @lay foo = ... in ...
+で他レイヤに重ね書きするためであります。
))
-
+)
))
@@ -185,24 +211,55 @@
自分にないフィールドの場合は親に問い合わせが行く感じになっていますが、
フィールドの書き換えがないので、これは特に意味ないかもしれない…。
))
$(SECTION パターンマッチ, $(SECBODY
-pattern matching is also available. Here is an example.
-
- def adjSum(lst)
- {
- case( lst )
- when( {car:x, cdr:{car: y, cdr:z}} ) { {car: x+y, cdr: adjSum(z)} }
- when( {car:x, cdr:{}} ) { {car: x, cdr: {}} }
- when( {} ) { {} }
- };
-
-It is expanded to a sequence of if-then-elses prefering the first-match.
-Note that {a: _} pattern matches all the tables that have the .a field.
-It also matches to {a: 123, b: 456} having extra .b field. So, changing the
-order of "when"s in the above code changes the behavior.
+
))
)
))
@@ -357,15 +414,43 @@
/}
its corresponding arguments are evaluated in the layer and passed to it.
If you specify multiple layers, the argument expression is run multiple times.
If you do not specify any layer for a parameter, it works in the neutral layer.
+
+))
+$(SECTION Macro Layers, $(SECBODY
+
When function is invoked, it first run in the @macro layer, and after that,
it run in the neutral layer. Here is an example.
>> @macro twice(x) { x; x }
>> def f() { twice(print("Hello")); 999 }
@@ -382,11 +467,36 @@
execute as a function. Resulting syntax tree is
"print("Hello"); print("Hello"); 999"
and this is executed on the neutral (in this example, @value) layer.
This is the reason why you see two "Hello"s.
+ [[quote and unquote]]
+ Here is more involved example of code genration.
+ From "x", it generates "x*x*x*x*x*x*x*x*x*x".
+
+ @macro pow10(x) {
+ @value(
+ def pow(x, n) {
+ if( n == 1 ) { x }
+ else {
+ @macro( @value(x) * @value(pow(x,n-1)) )
+ }
+ }
+ in
+ pow(@macro(x),10)
+ )
+ };
+
+ Here, x is a syntax tree but n is an actual integer. If you read carefully,
+ you should get what is going on. Basically, @macro can be considered like
+ quasiquoting and @value to be an escape from it.
+
+))
+$(SECTION 微妙な挙動, $(SECBODY
+
+ (rawmacro) レイヤの話
[[limitations]]
This @macro layer is a very primitive one, and not a perfect macro language.
Two major limitations are seen in the following "it" example.
@@ -409,35 +519,13 @@
>> LetItBe( 1+2+3, it*it )
...\value.d(173): [:24:1] variable LetItBe is not set in layer @value
you cannot directly use the macro in the same scope as the definition.
You need to wrap it up in a function (like the foo() in the above example).
-
-
-
- [[quote and unquote]]
-
- Here is more involved example of code genration.
- From "x", it generates "x*x*x*x*x*x*x*x*x*x".
-
- @macro pow10(x) {
- @value(
- def pow(x, n) {
- if( n == 1 ) { x }
- else {
- @macro( @value(x) * @value(pow(x,n-1)) )
- }
- }
- in
- pow(@macro(x),10)
- )
- };
-
- Here, x is a syntax tree but n is an actual integer. If you read carefully,
- you should get what is going on. Basically, @macro can be considered like
- quasiquoting and @value to be an escape from it.