`, and escaping from them with comma , or comma-at ,@, perhaps nestedly so. One day I realized this syntax is similar to GStrings in Groovy, which are quoted with double-quote " and escaped with dollar $, perhaps nestedly so. Lisp symbols are similar to Java interned strings. I wondered if GString syntax be used to specify syntactic macros in Groovy.In Paul Graham's online book, On Lisp, he describes how to write a macro:
(defmacro nil! (var) `(setq ,var nil))Using GString notation, we could define an equivalent macro in Groovy by writing:
defMacro("setq($var, null)"){"nilBang($var)"}For Groovy to match Lisp in functionality, we would need two more functions:
'[sum, a, b]'.asFunc() == 'sum(a, b)''[+, a, b]'.asFunc() == '(a + b)'and:
"[a, $b, c]".expand() == [a, 2, c]as well as the already-provided:
"[$a, $b]".evaluate() == 3Paul Graham writes that when using the backquote in Lisp:
`(a b c) is the same as '(a b c)and
`(a b c) is the same as (list 'a 'b 'c)With Groovy syntactic macros:
"[a, b, c]" will be the same as '[a, b, c]'and
"[a, b, c]" the same as ["a", "b", "c"].Using the comma with the backquote in Lisp:
`(a ,b c ,d) is the same as (list 'a b 'c d)With Groovy macros:
"[a, $b, c, $d]" will be the same as ["a", b, "c", d]In Lisp, if we assign some values using
(setq a 1 b 2 c 3), then we'll get:> `(a ,b c)
(A 2 C)In Groovy, if we assign using
def a=1, b=2, c=3, then we would get:assert "[a, $b, c]".expand() == [a, 2, c]For an example with nesting using these values:
> `(a (,b c))
(A (2 C))In Groovy it would be:
assert "[a, [$b, c]]".expand() == [a, [2, c]]A more complex example from On Lisp:
> `(a b ,c (',(+ a b c)) (+ a b) 'c '((,a ,b)))
(A B 3 ('6) (+ A B) 'C '((1 2)))In Groovy it would be:
assert "[a, b, $c, ['${"[+, a, b, c]".asFunc()}'], " +
"[+, a, b], 'c', '[[$a, $b]]']".expand() ==
[a, b, 3, ['6'], [+, a, b], 'c', '[[1, 2]]']Another example, in Lisp:
`(,a ,(b `,c))and in Groovy:
"[$a, ${[b, "$c"]}]"We'd need to introduce some additional syntax to match the comma-at notation from Lisp:
> (setq b ’(1 2 3))
(1 2 3)
> `(a ,b c)
(A (1 2 3) C)
> `(a ,@b c)
(A 1 2 3 C)The Groovy equivalent, with additional syntax
$* to show interpolate-with-spreading, would be:def b= [1, 2, 3]
"[a, $b, c]".expand == [a, [1, 2, 3], c]
"[a, $*b, c]".expand == [a, 1, 2, 3, c]I'm nowhere near providing this sort of functionality in Groovy/DLR, but such self-referential syntactic macros would complement the recently added AST macro system in Groovy 1.6.
2 comments:
Have you seen the slides for my Groovy AST transforms talk? http://is.gd/XdUR
It covers this exact example (nil!) and talks about what can be done. After the work with GEP-2 (http://docs.codehaus.org/display/GroovyJSR/GEP+2+-+AST+Builder+Support) is done in a few weeks I plan on taking a look at macros. However, I think the Boo metamethod approach is a more promising parallel for Groovy than Lisp macros. A metamethod takes as parameters Expressions and always returns a List<Expression>. A transform handles converting calling code into a macro call and back into code. SO nil!/setNull could be this (with no language syntax change needed):
@Macro
def setNull(Expression e) {
// write AST to set the VariableExpression e to null
}
// call code
def x = 5
setNull(x)
assert 5 == null
sorry, last line should be:
assert x == null
Post a Comment