Differences From Artifact [b31646ec7576a8a6]:
- File
sample/macro.pmy
- 2010-11-24 12:14:00 - part of checkin [3ae09b8cbf] on branch trunk - changed if-then-else syntax (user: kinaba) [annotate]
To Artifact [996468a22f9d9a8e]:
- File
sample/macro.pmy
- 2010-11-25 03:32:41 - part of checkin [474c4facf0] on branch trunk - Introduced makefile to build documents. sample/macro.pmy is fully reformed. print(x) now returns x, not 0. (user: kinaba) [annotate]
> 1 ########################################
> 2 print("----------");
> 3
1 @macro twice = fun(x) { x; x }; | 4 @macro twice = fun(x) { x; x }; # Hello Hello
2 @macro max(x,y) { <
3 var _x = x; # no hygenic macro btw.... <
4 var _y = y; # no hygenic macro btw.... <
5 if(_x<_y)then _y else _x | 5 twice( print("Hello") );
6 }; <
7 def maxNormal(x,y) { <
> 6
> 7 ########################################
8 if(x<y) | 8 print("----------");
9 then: y <
10 else: x <
11 }; <
> 9
12 @macro maxBad(x,y) { 10 @macro maxBad(x,y) {
13 if x<y: y else: x | 11 if x<y then y else x
> 12 };
> 13 @macro maxGood(x,y) {
> 14 var _x = x; # NOTE: no hygenic macro
> 15 var _y = y;
> 16 if _x < _y then _y else _x
14 }; 17 };
15 <
16 @macro LetItBe(x, y) { let it = x in y }; <
17 <
18 @macro pow10(x) { <
19 @value( <
20 def pow(y, n) { <
> 18 def maxFun(x,y) {
21 if( n == 1 ) then y | 19 if x<y then y else x
22 else <
23 @macro( @value(y) * @value(pow(y,n-1)) ) <
24 } <
25 in <
26 pow(@macro(x+1),10) <
27 ) <
28 }; 20 };
> 21 @macro maxGreat(x,y){@value(
> 22 var nx = gensym(); # generate fresh symbol
> 23 var ny = gensym();
> 24 @macro _x = @macro(nx) {name: nx}; # cheating to create {is:"Var" .. }
> 25 @macro _y = @macro(ny) {name: ny}; # at macro layer
> 26 {is: "Let", name: nx, layer: "", init: @macro(x), expr:
> 27 {is: "Let", name: ny, layer: "", init: @macro(y), expr:
> 28 @macro(if _x < _y then _y else _x)}} # the expression
> 29 )};
29 30
30 @macro pow10Hard(x) { | 31 print( maxGood(print(1), print(2)) ); # 1 2 2
31 @value( | 32 print( maxBad(print(1), print(2)) ); # 1 2 2 2
32 def pow(x, n) { | 33 print( maxFun(print(1), print(2)) ); # 1 2 2
33 if( n == 1 ) then x | 34 print( maxGreat(print(1), print(2)) ); # 1 2 2
34 else | 35 print( maxGreat(print(2), print(1)) ); # 2 1 2
35 @macro( @value(x) * @value(pow(x,n-1)) ) <
36 } | 36
> 37 ########################################
37 in | 38 print("----------");
38 pow(@macro(x+1),10) <
39 ) | 39
> 40 # the variable "it" is inserted to the scope
> 41 @macro LetItBe(x, y) { let it = x in y };
> 42 print( LetItBe("myself", "when I find " ~ it ~ " in times of trouble") );
> 43
> 44 ########################################
> 45 print("----------");
> 46
> 47 # layerd parameter can also be used for @macro
> 48 # you can mix @macro and normal parameters!!
> 49 def 3way(n, c1 @macro, c2 @macro, c3 @macro)
> 50 {
> 51 case n*n
> 52 when 0: c1
> 53 when 1: c2
> 54 when 4: c3
40 }; 55 };
41 56
42 def printAndReturn(x) | 57 3way( rand(3), print("One"), print("Two"), print("Three") );
> 58 3way( rand(3), print("One"), print("Two"), print("Three") );
> 59 3way( rand(3), print("One"), print("Two"), print("Three") );
43 { | 60
> 61 ########################################
44 print(x); | 62 print("----------");
45 x | 63
> 64 # Conversely, we can mix @value parameter in the macro definition
> 65 @macro times(n @value, e) { @value(
> 66 if n == 1 then
> 67 @macro(e)
> 68 else
> 69 @macro(e; times(n-1,e))
46 }; | 70 )};
> 71 times(7, print("Ichimen no Nanohana"));
> 72
> 73 # Here, n is bound to the integer 7, not the AST of it.
> 74
> 75 ########################################
> 76 print("----------");
> 77
> 78 # Explicit manipulation of AST.
> 79 # Reverse the order of arguments of the function call expression
> 80 @macro reverseArgs(e) {@value(
> 81 def rev(xs, acc) {
> 82 case xs when {car:x, cdr:xs}: rev(xs, {car:x, cdr:acc}) when {}:
> 83 };
> 84 case @macro(e)
> 85 when {is:"App", fun:f, args:as}: {is:"App", fun:f, args:rev(as,{
> 86 when e : e
> 87 )};
> 88 print( reverseArgs(1+2) ); # 2+1 == 3
> 89 print( reverseArgs(1-2) ); # 2-1 == 1
> 90
> 91 ########################################
> 92 print("----------");
> 93
> 94 # Both prints "original". Macro respects the neutral layer's "let y="
> 95 # and "fun(y)". It does not alter the inner scope y
> 96 @macro test1(y) { fun(y){y}("original") };
> 97 @macro test2(y) { let y = "original" in y };
> 98 print( test1("replaced?") );
> 99 print( test2("replaced?") );
> 100
> 101 ########################################
> 102 print("----------");
> 103
> 104 # Macro expansion is done only at the first call.
> 105 # So by using @macro parameter, it can remember the argument
> 106 # of the first call.
> 107 def remember1( x @macro, y ) { if x == y then "yes" else "no" };
> 108 print( remember1(1, 1) ); # yes 1 == 1
> 109 print( remember1(2,1) ); # yes "1" == 1
> 110 print( remember1(2,2) ); # no "1" != 2
> 111
> 112 # exactly the same function, but called in different order
> 113 def remember2( x @macro, y ) { if x == y then "yes" else "no" };
> 114 print( remember2(2, 2) ); # yes "2" == 2
> 115 print( remember2(2, 1) ); # no "2" != 1
> 116 print( remember2(1, 1) ); # no "2" != 1
> 117
> 118 # Is this a good thing or a bad thing??
47 119
48 def main() <
49 { <
50 twice( print("foo") ); <
> 120 ########################################
51 print("--------------"); | 121 print("----------");
52 print(max(printAndReturn(100),printAndReturn(200))); <
53 print("--------------"); <
54 print(maxNormal(printAndReturn(100),printAndReturn(200))); <
55 print("--------------"); <
56 print(maxBad(printAndReturn(100),printAndReturn(200))); <
57 print("--------------"); <
58 print( LetItBe( 1+2+3, it*it ) ); <
59 print("--------------"); <
60 print(pow10(1)); <
61 print(pow10(2)); <
62 print("--------------"); <
63 print(pow10Hard(1)); <
64 print(pow10Hard(2)); <
65 }; <
66 122
67 main(); | 123 # Trick to extract the AST of a function
> 124 def foo(x) { x + x };
> 125 print( @macro(@value(foo)(arg1)) ); # prints AST for "arg1 + arg1"
68 126
> 127 # If we wrote @macro(foo(arg1)), it is the AST of "foo(arg1)"
> 128 # Here, by @value(foo) we obtain the "usual" behavior of foo,
> 129 # not the macro-like bahavior to construct AST "foo(??)".
> 130 # But still, by @macro( ... ) layer, the "usual" function is run in
69 @macro foo(y) | 131 # macro mode.
70 { <
71 fun(y){y}(300) <
72 # let y = 300 in y <
73 }; <
74 <
75 print("--------------"); <
76 print(foo(200)); <