at:tutorial:metaprogramming
Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
at:tutorial:metaprogramming [2007/07/27 07:21] – jdedecker | at:tutorial:metaprogramming [2009/11/21 07:44] (current) – tvcutsem | ||
---|---|---|---|
Line 1: | Line 1: | ||
===== Metaprogramming ===== | ===== Metaprogramming ===== | ||
- | ==== AT Zero - AmbientTalk without syntactic sugar ==== | + | ==== AmbientTalk without syntactic sugar ==== |
In AmbientTalk, | In AmbientTalk, | ||
Line 25: | Line 25: | ||
==== Quasiquoting and splicing ==== | ==== Quasiquoting and splicing ==== | ||
+ | Quasiquoting and splicing are an advanced and powerful metaprogramming techniques that control the evaluation process and allow one to manipulate the evaluation process of the abstract syntax tree. | ||
- | === Qouting | + | === Quoting |
Any valid AmbientTalk expression can be quoted. This prevents the expression from being evaluated. Instead, it is returned literally. | Any valid AmbientTalk expression can be quoted. This prevents the expression from being evaluated. Instead, it is returned literally. | ||
Line 59: | Line 60: | ||
</ | </ | ||
- | Note that in '' | + | Note that in '' |
== Expressions == | == Expressions == | ||
- | To quote a complete expression, it has to be wrapped in parantheses: | + | To quote a complete expression, it has to be wrapped in parentheses: |
< | < | ||
Line 78: | Line 79: | ||
== Statements == | == Statements == | ||
- | Statements (definitions, | + | Statements (definitions, |
< | < | ||
Line 101: | Line 102: | ||
With this construct, all the elements of the literal table are evaluated. By quoting a literal table, all the elements are quoted instead of evaluated: | With this construct, all the elements of the literal table are evaluated. By quoting a literal table, all the elements are quoted instead of evaluated: | ||
< | < | ||
- | > | + | > |
>> | >> | ||
</ | </ | ||
Line 127: | Line 128: | ||
>[ 7, 8, 9, @upTo(4) ] | >[ 7, 8, 9, @upTo(4) ] | ||
>>[7, 8, 9, 1, 2, 3, 4] | >>[7, 8, 9, 1, 2, 3, 4] | ||
+ | >[ 7, 8, 9, upTo(4) ] | ||
+ | >>[7, 8, 9, [1, 2, 3, 4]] | ||
</ | </ | ||
+ | In the example above the elements of the table returned by invoking **upTo(4)** are added in place to the table in which the expression was spliced. | ||
Splicing can also be used in combination with quoting and unquoting. AmbientTalk provides the // | Splicing can also be used in combination with quoting and unquoting. AmbientTalk provides the // | ||
Line 191: | Line 195: | ||
>read: " | >read: " | ||
>> | >> | ||
- | >eval: `(1+2) in: self | + | >def result := eval: `(1+2) in: self |
>>3 | >>3 | ||
- | > | + | > |
- | >>" | + | >>" |
</ | </ | ||
Line 201: | Line 205: | ||
< | < | ||
>def o := object: { def x := 4 } | >def o := object: { def x := 4 } | ||
- | >>< | + | >>< |
>eval: `x in: o | >eval: `x in: o | ||
>>4 | >>4 | ||
</ | </ | ||
+ | |||
+ | ==== Multi-stage (Generative) Programming ==== | ||
+ | |||
+ | Here's a small example of " | ||
+ | |||
+ | Below is a regular power function. Given two numbers ' | ||
+ | |||
+ | <code javascript> | ||
+ | def pow(x, n) { | ||
+ | if: (n == 0) then: { | ||
+ | 1 | ||
+ | } else: { | ||
+ | x * pow(x,n-1); | ||
+ | } | ||
+ | }; | ||
+ | </ | ||
+ | |||
+ | Let's see whether it works: | ||
+ | <code javascript> | ||
+ | system.println(pow(2, | ||
+ | </ | ||
+ | |||
+ | Now, consider the following ' | ||
+ | |||
+ | <code javascript> | ||
+ | def expandPow(var, | ||
+ | if: (n == 0) then: { | ||
+ | `1 // `exp returns an abstract syntax tree for exp | ||
+ | } else: { | ||
+ | // within a quoted expression, #(exp) evaluates exp, | ||
+ | // expects it to return an AST, and embeds that AST | ||
+ | // in the quoted expression | ||
+ | `(#var * # | ||
+ | } | ||
+ | }; | ||
+ | |||
+ | // this prints the expression 'y * y * y * 1' | ||
+ | system.println(" | ||
+ | </ | ||
+ | |||
+ | To be able to use the expression generated by the above function, let's define a small helper function that will embed this expression in a first-class function: | ||
+ | |||
+ | <code javascript> | ||
+ | def powMaker(n) { | ||
+ | def ast := expandPow(`x, | ||
+ | // the built-in function ' | ||
+ | // evaluates the expression in the scope of the given object | ||
+ | // return a function that has the expanded expression as its body: | ||
+ | eval: `({|x| #ast}) in: self; | ||
+ | }; | ||
+ | </ | ||
+ | |||
+ | Now we can generate power functions that are fixed in their second argument, but that are more efficient to execute: | ||
+ | |||
+ | <code javascript> | ||
+ | // pow5 is now bound to a function { |x| x*x*x*x*x*1 } | ||
+ | def pow5 := powMaker(5); | ||
+ | |||
+ | system.println(pow5(2)); | ||
+ | </ | ||
+ | |||
+ | You can measure the performance difference by timing the evaluation of both functions: | ||
+ | |||
+ | <code javascript> | ||
+ | import / | ||
+ | system.println(" | ||
+ | system.println(" | ||
+ | </ | ||
+ | |||
+ | The quoting and unquoting mechanism of AmbientTalk makes it really easy to " | ||
+ | |||
+ | The above example is available in the AmbientTalk library, under '/ |
at/tutorial/metaprogramming.1185513710.txt.gz · Last modified: 2007/07/27 07:45 (external edit)