
Macros in Perl6 - drewr
http://strangelyconsistent.org/blog/macros-what-are-they-really
======
paulkoer
This is interesting. You can manipulate the AST in other languages of course,
for example Python. However these ASTs are so difficult to handle that
programmers don't really want to work with them (see point 12. on bottom of
the page <http://norvig.com/python-lisp.html>).

I think Paul Graham wrote that any language implementing macros with Lisp-
power will effectively have to introduce something that is 'as bad or worse
than the parenthesis'. [1] It will be interesting to see how this will play
out in Perl6.

However the example given in this article is pretty limited, so I think we
can't really tell based on that. It also begs the question 'Why not use a
function?', i.e. it is not a case where one needs a macro. It will be
interesting to see how Perl6 handles real macro use cases where you have to do
heavy AST manipulation. I think here the Lisp syntax is really showing its
strengths because you don't have to think in terms of a different
representation that you don't have in front of you.

[1] See text after the 1-9 list. <http://www.paulgraham.com/icad.html>

Edit: Better source for [1].

~~~
draegtun
_It also begs the question 'Why not use a function?', i.e. it is not a case
where one needs a macro_

The (last) example is best being a macro because it avoids running that
_crazily-expensive-computation()_ whereas a function would evaluate it.

~~~
Xurinos
The argument on the delayed execution issue is that you could just wrap
crazily-expensive-computation() in a lambda/sub that is executed
conditionally.

~~~
draegtun
Indeed. However I do like the fact that Perl6 macros & functions use the same
calling syntax and so are _often_ interchangeable.

------
draegtun
Nice post. Puts more flesh on the bone than some previous examples i've seen
(for eg: <http://en.wikipedia.org/wiki/Perl_6#Macros>).

------
buster
And this is called the good kind of macros.. i'm not sure if i want to ever
see someone manipulating the AST in his code.. i don't know Lisp and he says
that this is what makes Lisp the awesome language it is, but to me it sounds
scary and dangerous and inconsistent..

~~~
Xurinos
I am a Lisp newbie. Here is, effectively, the Lisp equivalent, along with the
typical Lisp style guidelines:

    
    
      (defconstant +logging-enabled+ t)
    
      (defmacro log-message (message)
        (when +logging-enabled+
             `(err-say ,message)))
    
      (log-message (crazily-expensive-computation))
    
    

Like other structures, they can be abused or used with great success. Based on
my limited experience with a number of quicklisp-downloaded packages, I have
found macros helpful and unnoticeable as macros.

Irony: Fewer bracing symbols.

In the next blog post, I am hoping to see how perl 6's macro feature handles
the parsing of passed-in code. Specifically, I would like to see an example
for do-in-reverse:

    
    
      (defmacro do-in-reverse (&body commands)
        `(progn ,@(reverse commands)))
    
      (do-in-reverse
        (princ "First")
        (princ "Second")
        (princ "Third")))
    
    

Prints "ThirdSecondFirst"

~~~
perlgeek
There isn't yet any API for introspecting ASTs ("parsing of passed-in code" as
you call it), nor for programmatically constructing new AST nodes. Such things
will hopefully emerge once macro implementation and specification become more
concrete.

So I can only guess what it would look like; take the following with a rock of
salt:

    
    
        macro do-in-reverse($code) {
             $code.clone(statements => $code.statements.reverse);
        }
    
        do-in-reverse {
            say 'First';
            say 'Second';
            say 'Third';
        };
    

But it might turn out not be that simple.

The diffulcty comes from the fact that unlike Lisp, in Perl 6 not everything
is a list, so you can't treat the AST as a list (... of lists, possibly)
either. The .clone would take care to preserve things like outer lexicals and
the signature of the block (you don't see it; it's implicit) and other non-
listy things.

~~~
draegtun
So potentially not to different to how you might do it in Io
(www.iolanguage.com):

    
    
        doInReverse := method (
            m     := call argAt(0)
            stmts := list()              // list of statements (ie. messages)
        
            loop (
                rest := m next           // rest of messages after current 
                stmts append(m setNext)  // get current message
                m := rest
                if (m == nil, break)     // exhausted statements when "nil"
            )
    
            stmts reverseForeach (n, doMessage(n))
        )
    
        doInReverse( 
            writeln("First") 
            writeln("Second") 
            writeln("Third") 
        )
    

Of course this is easy in Io because everything is just a message.

NB. The above code doesn't actually amend the AST but it could. Here are some
previous examples of amending AST in Io posted here:
<http://news.ycombinator.com/item?id=1810480>
<http://news.ycombinator.com/item?id=1804599>

