# [Openmcl-devel] macroexpand-all

Ron Garret ron at flownet.com
Wed Jun 25 09:19:07 PDT 2014

```BTW, one of the spiffy things you can do with combination-hook is define a currying Lisp-1 lambda:

(defun convert-args (args)
(cond ( (null args) nil )
( (atom args) (list '&rest args) )
(t (cons (car args) (convert-args (cdr args))))))

(defmacro λ (args &body body)
(let ((args (remove-if (lambda (x) (eql #\& (elt (symbol-name x) 0))) args)))
`(lambda ,(convert-args args)
(flet ,(mapcar (lambda (arg) `(,arg (&rest args) (apply ,arg args))) args)
, at body))))

which then lets you e.g. compute a factorial using a Y combinator without having to put FUNCALLs in all over the place:

? (((λ (f) ((λ (g) (g g)) (λ (h) (λ (x) ((f (h h)) x)))))
(λ (f) (λ (n) (if (zerop n) 1 (* n (f (1- n)))))))
10)
3628800

You can even do the same thing using Church numerals:

? ((λ (f s) (f (s (s (s (f (s (s (s (λ (f x) x))))))))))
(λ (n f) (n (λ (c i) (i (c (λ (f x) (i f (f x))))))
(λ x f) (λ x x)))
(λ (n f x) ((n f) (f x)))
'1+ 0)
362880

Note that this code does not invoke any CL functions except 1+, which is only used to convert the resulting Church numeral into a integer.

rg

On Jun 25, 2014, at 8:59 AM, Ron Garret <ron at flownet.com> wrote:

>
> On Jun 25, 2014, at 12:58 AM, Tim Bradshaw <tfb at tfeb.org> wrote:
>
>> On 24 Jun 2014, at 21:46, Taoufik Dachraoui <dachraoui.taoufik at gmail.com> wrote:
>>
>>> 3.1.2.1.2' .... "If the car of the compound form is not a symbol, then that car is either a lambda expression in which case the compound form is a lambda form or it is a macro form ..." ...
>>>
>>> Does this contradict anything else in the spec?
>>
>> Not really, I think. Its not self-consistent as it stands because in ((lambda ...) ...) the car of the form is both a lambda form and a macro form, but this can be easily resolved.  However restricting it to a macro form is silly: just let it be a form which will be compiled in the normal way, leading to a semantics which is essentially a Lisp 2 with a fallback Lisp 1 in the case that the car of the form is not a symbol.  I can imagine people not liking that but I'd be happy with it.  That clause would then read something like
>>
>> "If the car of the compound form is not a symbol then it is a form which will be evaluated and should return a function …"
>
> Unfortunately, while this makes perfect sense if you apply common sense, it doesn’t actually work with respect to the rest of the spec, because forms whose cars are functions are also errors in CL as it currently stands.
>
>> (Note you no longer need the special case for ((lambda ...) ...) which is nice).
>
> Indeed it would be.
>
>> I think this is the semantics that Ron's hack (meant in a good way) implements.
>
> COMBINATION-HOOK is actually more general than that.  It takes a form ((…) …) and essentially turns it into an anonymous macro whose macroexpander is the function COMBINATION-HOOK.  When COMBINATION-HOOK is defined thusly:
>
> (defun combination-hook (form) (cons 'funcall form))
>
> then it does what you describe.  IMHO this is the only possible sane definition of COMBINATION-HOOK, but when I proposed this on C.L.L. many years ago I was met with a flood of objections (the details of which I can no longer recall) so I made it as general as I possibly could.
>
>> The only thing that *can't* work is that you can return a macro function there, as that would make compilation impossible.
>
> Actually, this is possible (though not advisable IMHO).  COMBINATION-HOOK is invoked at compile time.  It is, essentially, a macro-expander for the “anonymous macro” ((…) …).  So, for example, you could turn this into a non-anonymous macro:
>
> (defmacro combination-hook-macro (&rest form)
>  (let ((frob (ignore-errors (eval (car form)))))
>    (if (and frob (symbolp frob))
>      (cons frob (cdr form))
>      (cons 'funcall form))))
>
> (defun combination-hook (form) (cons 'combination-hook-macro form))
>
> ? (defmacro foo (&rest body) `(progn (print 'foo) , at body))
> FOO
> ? (defmacro baz (&rest body) `(progn (print 'baz) , at body))
> BAZ
> ? ((IF (ODDP (RANDOM 10)) 'FOO 'BAZ) 123)
>
> FOO
> 123
> ? ((IF (ODDP (RANDOM 10)) 'FOO 'BAZ) 123)
>
> BAZ
> 123
>
> rg
>
> _______________________________________________
> Openmcl-devel mailing list
> Openmcl-devel at clozure.com
> http://lists.clozure.com/mailman/listinfo/openmcl-devel

```