## Macros

You have problems, and we're glad to hear them. Explain the problem, what you have tried, and where you got stuck.
Feel free to share a little info on yourself and the course.
Forum rules
Please respect your teacher's guidelines. Homework is a learning tool. If we just post answers, we aren't actually helping. When you post questions, be sure to show what you have tried or what you don't understand.

### Macros

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 .
omarasl

Posts: 12
Joined: Sun Nov 25, 2012 6:19 am

### 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

nuntius

Posts: 532
Joined: Sat Aug 09, 2008 10:44 am
Location: Newton, MA

### Re: Macros

omarasl

Posts: 12
Joined: Sun Nov 25, 2012 6:19 am

### Re: Macros

Well. Common Lisp macroes are easy when the problem is easy.
A little example here:
Code: Select all
`;; 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:

Code: Select all
`;; 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:
Code: Select all
`(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
sylwester

Posts: 130
Joined: Mon Jul 11, 2011 2:53 pm

### Re: Macros

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 ) ?????????
omarasl

Posts: 12
Joined: Sun Nov 25, 2012 6:19 am

### Re: Macros

For better understanding
if you have a macro:
Code: Select all
`(defmacro add10-m (num)  `(+ 10 ,num))`

you can also have a function with quasiquotation:
Code: Select all
`(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:
Code: Select all
`(add10-f '(+ 1 2))`

or more clearly:
Code: Select all
`(add10-f (list '+ 1 2))`

and it returns:
Code: Select all
`(+ 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:
Code: Select all
`(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:
Code: Select all
`(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:
Code: Select all
`(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.

Goheeca

Posts: 271
Joined: Thu May 10, 2012 12:54 pm

### Re: Macros

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:
Code: Select all
`(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:
Code: Select all
`(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
sylwester

Posts: 130
Joined: Mon Jul 11, 2011 2:53 pm

### Re: Macros

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.
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.

Goheeca

Posts: 271
Joined: Thu May 10, 2012 12:54 pm

### 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
I'm the author of two useless languages that uses BF as target machine.
Currently I'm planning a Scheme compiler :p
sylwester

Posts: 130
Joined: Mon Jul 11, 2011 2:53 pm