This is a read-only archive of lispforum.com. The forum was locked to new users and posts and is preserved here as static HTML from a database snapshot taken on 2019-09-07.

Macros

9 posts · 11535 views

Hello everybody ,
can someone help me in macros .
are there any useful books or sites which contains good examples of macros .
Actually , I have some functions about sorted list and binary trees, I have to write the same functions by using macros .
I don`t know how , and my functions are not short (about 9 functions) .
so if there is someone can help me , I will put the code to discuss about it .
Thank you very much .

Re: Macros

Which dialect are you using? Scheme and CL have significantly different macro systems...

The following sources describe CL macros.

Practical Common Lisp has a couple introductory chapters

On Lisp has much deeper coverage

Re: Macros

thanks for your reply , actually my question about common lisp macros

Re: Macros

Well. Common Lisp macroes are easy when the problem is easy.
A little example here:
;; function
(defun add10 (num)
   (+ 10 num))
Now a macro i CL is a function with the source arguments as parameters and the result is what the CL actually evaluates.
It means you would make a macro with the body evaluating to the list structure (+ 10 <whatever you put as num>) like this:
;; old style, but more verbose and less easy to read (when macro is more complex)
(defmacro add10 (num)
  (list '+ 10 num))

;; or by using quasiquote
(defmacro add10 (num)
  `(+ 10 ,num))
So when you write (add10 (+ 3 5)) add10 is expanded with (+ 3 5) as num and the result is (+ 10 (+ 3 5)).
Being so simple it does not have problems with variable capturing (hygiene), arguments being evaluated more than once and sometimes in the wrong order, but for real life situations those things are what makes CL macros difficult to master. When testing macros you should always try arguments with side effects like (add10 (print 10)) that should print 10 once and evaluate to 20. With more arguments they should print in order once each before returning whatever it should. Use this to see what your macro does and what gets feed to CL:
(macroexpand-1 '(add10 (print 10))) 
==> (+ 10 (PRINT 10))
Have fun :)
I'm the author of two useless languages that uses BF as target machine.
Currently I'm planning a Scheme compiler :p

Re: Macros

thanks for replying
as I understand ( maybe I understood wrong) that we can replace the function to macro by simple changes in code , is it right?????
for example if I have this function which use to insert in Binary search tree :


(defun BST-insert (B E)
(if (BST-empty-p B)
(make-bin-tree-leaf E)
(BST-nonempty-insert B E)))

how I can make macro instead of this function (with the same internal code ) ?????????

Re: Macros

For better understanding
if you have a macro:
(defmacro add10-m (num)
  `(+ 10 ,num))
you can also have a function with quasiquotation:
(defun add10-f (num)
  `(+ 10 ,num))
The difference is that macros are evaluated in compile-time and get unevaluated arguments. Back to the aforedefined function, the function can be called like this:
(add10-f '(+ 1 2))
or more clearly:
(add10-f (list '+ 1 2))
and it returns:
(+ 10 (+ 1 2))
But we give it only data and get data from it too, coincidentally they look like code (on the input side we reached it with quote -- that apostrophe). If we use a macro instead of a function for example:
(add10-m (+ 1 2))
The compiler invokes the macro function and passes the calling form* to that function (it's nicely parsed, due to the lambda-list in a defmacro form) so we don't quote, it does the compiler.
The macro function returns something which is expected to be code which is processed by the compiler further and afterwards the result of compilation is evaluated during run-time.
The macro can be written with the help of our function:
(defmacro add10-m (num)
  (add10-f num))
Maybe will help you the information: in CL beside macros exist reader macros which take part during read-time, the key is to realise differences among run-time, compile-time and read-time. At least for me it was the key, but reader macros are beyond this single post.
Rather try this sample:
(defmacro some-value () (read))
(defun add (num) (+ num (some-value))
(add 10)
After typing defun form (insert the code into REPL line by line) it will hang because of read so type some lisp form which evaluates to number and try the new defined function; it won't hang because there is no read in that function.

*Compare function lambda-list and macro one (for example &whole keyword).
cl-2dsyntax is my attempt to create a Python-like reader. My mirror of CLHS (and the dark themed version). Temporary mirrors of aferomentioned: CLHS and a dark version.

Re: Macros

omarasl wrote:thanks for replying
as I understand ( maybe I understood wrong) that we can replace the function to macro by simple changes in code , is it right?????
for example if I have this function which use to insert in Binary search tree :


(defun BST-insert (B E)
(if (BST-empty-p B)
(make-bin-tree-leaf E)
(BST-nonempty-insert B E)))

how I can make macro instead of this function (with the same internal code ) ?????????
Change the function so that when run it will return like this:
(defun BST-insert (B E) ...)

(BTS-insert 'q 'w) ==>
(if (BST-empty-p q)
      (make-bin-tree-leaf w)
    (BST-nonempty-insert q w))
Then change from defun to defmacro. It's not perfect since B might be (make-bin-tree-leaf e) so you should make sure every argument is used exactly once in the resulting code. E is used twice but in different branches so is ok, but B is used twice in one workflow and should be rewritten:
(BTS-insert '(make-bin-tree-leaf e) 'w) ==>
(let ((tmpvar  (make-bin-tree-leaf e)))
  (if (BST-empty-p tmpvar)
      (make-bin-tree-leaf w)
    (BST-nonempty-insert tmpvar w)))
Then you should use gensym in the macro to make tmpvar a unique symbol for each run.
I'm the author of two useless languages that uses BF as target machine.
Currently I'm planning a Scheme compiler :p

Re: Macros

Goheeca wrote:And after you get hygiene and a multiple evaluation issue you can stop reinventing the wheel and use well-known macros: with-gensyms & once-only.
Useful, but learning Lisp is all about reinventing the wheel 8-)
I'm the author of two useless languages that uses BF as target machine.
Currently I'm planning a Scheme compiler :p