On Macros

Started by PapoAnaya, April 21, 2012, 01:28:32 PM

Previous topic - Next topic

PapoAnaya

Hi:

One post in comp.lang.lisp stated that "thou shall know macros to get thy mastery of ye LISP arcana", hence decided to explore macros for fun and amusement. Sadly here in the forum if you do a search on  macro (or define macros) nothing shows up, hence decided to write a small post about macros.



(define-macro ) in newlisp creates functions in which the arguments are not evaluated. In lay person terms, f you have a variable x with a value of 10, and x is being passed to a macro, then "x" is the value that is obtained from the argument and not 10.  You can look for fexpr in your favorite search engine for the details on implementation and how it differs from macro in common lisp.  More details can also be found in the newlisp manual.



Well,  this sounds nice and dandy, but what can you do with such thing.



I'm placing two examples of macros that come directly from the gnulisp manual. Only that they are implemented in newlisp (obviously :) )  It really does not have a lot of changes from the examples as written in the text.



The first one is  an implementation of the "inc" function using macros:




(define-macro (my-inc var)
  (eval (list 'setq var (list '+ 1 var) ))
)

(while (< i 10)
       (println (my-inc i))
)


The following must be noted:

[*] The macro is building code that will be evaluated. In this case, it is building

a list containing (setq i (+ 1 i))

  • [*] For the macro to execute, the created expression must be evaluated. If you

    substitute eval with println, you'll see aforementioned code. This is handy to

    debug macros.  An alternative of execution is to return the resultant list and

    modify it, but in this case, I wanted it only to execute; printing the numbers from 1 to 10.
  • [/list]

    The second example is a version of the for loop with syntactic sugar.




    (define-macro (mi-for var from init to final do body)
      (eval
      (list 'let (list (list var init))
            (cons 'while (cons (list '<= var final)
                               (append (list body) (list (list 'inc var))))))) )

    (mi-for i from 1 to 10 do
         (let ()
           (println i) )
    )



    [*] As you can see, it's another variation of the same theme. In this case

    it is building a while loop that will execute 10 times the content of the

    body.
  • [*] Being that the body is only one argument, it needs to be surrounded with a let

    function for all the statements to run.

  • [*] Eval is used to execute the code within the macro, but if substituting the eval with a println, this is what is obtained.
  • [/list]



    (let ((i 1))
     (while (<= i 10)
      (let ()
       (println i))
      (inc i)))


    This means that code can be built in a macro, returned from it and

    executed later on in your code.



    Hopefully this will help to those that are trying to understand these and hopefully find these examples useful.