[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: Expected behavior of CL special forms, 'labels' and 'flet', inside m
From: |
Pascal J. Bourguignon |
Subject: |
Re: Expected behavior of CL special forms, 'labels' and 'flet', inside macros. |
Date: |
Tue, 04 Aug 2009 03:49:38 +0200 |
User-agent: |
Gnus/5.1008 (Gnus v5.10.8) Emacs/22.3 (darwin) |
Jon Strait <jstrait@moonloop.net> writes:
> Hello,
>
> I thought I'd run this issue by the list in case someone who's worked
> on the CL extension code can say that it's the proper behavior and not
> worth submitting a bug report on.
>
> Basically, I tried using a 'labels' form to bind a function inside a
> macro to be used recursively and it wasn't working. (Lisp nesting
> exceeds max error) Then, I switched the 'labels' with 'flet', which
> ended up working fine, but not until after having to change the
> binding name as well. Using the same name for 'flet' as was previous
> used for 'labels' resulted in this strange error:
If you have a look at the macroexpansions, you will see that flet
shadows the original function name (and therefore it's understandable
that emacs lisp has difficulties if it was a macro), while labels
makes a substitution of the occurences of the defined functions.
> "Use `labels', not `flet', to rebind macro names"
>
> Is seems for some reason, the 'labels' functions binding name was
> registered with a macro name as well.
This could be considered a bug (vs. CL), or at least a feature
request, to have flet be able to shadow macros.
> Be advised, this is only in the context of testing both the macro and
> the calling code with eval-last-sexp inside a buffer.
>
> For the sample macro I created below, the first argument is a list of
> items and every subsequent argument is a lambda function taking one
> argument, to apply in sequence to the initial argument list using
> mapcar:
>
> (defmacro map-chain (init-list &rest mfuncs)
> (setq mfuncs (reverse mfuncs))
> (flet ((fmap (init-list mfuncs)
> (if (null mfuncs)
> init-list
> `(mapcar ,(car mfuncs) ,(fmap init-list (cdr mfuncs))))))
> (fmap init-list mfuncs)))
Or use let instead of setq:
(defmacro map-chain (init-list &rest mfuncs)
(let ((mfuncs (reverse mfuncs)))
(flet ((fmap (init-list mfuncs)
(if (null mfuncs)
init-list
`(mapcar ,(car mfuncs) ,(fmap init-list (cdr mfuncs))))))
(fmap init-list mfuncs))))
If flet was implemented with the same semantics as in Common Lips,
that macro wouldn't work. Indeed, you'd better use labels.
In Common Lisp:
C/USER[319]> (macroexpand '(map-chain '(7 8 9) (lambda (x) (* x 10)) (lambda
(y) (+ y 4))))
*** - EVAL: undefined function FMAP
It works in emacs lisp because flet is implemented as a dynamic
binding, and therefore when fmap is executing, fmap is fbound to the
redefinition.
In Common Lisp:
C/USER[322]> (defun example (x) (list 'toplevel x))
EXAMPLE
C/USER[323]> (flet ((example (x) (if (oddp x) (list 'lexical 'example x)
(example (1- x)))))
(values (example 1)
(example 2)))
(LEXICAL EXAMPLE 1) ;
(TOPLEVEL 1)
Both calls to example (example 1) and (example 2) call the lexical
local function. With x bound to 1, the first list is returned
directly; with x bound to 2, the toplevel function is called, from the
local funciton.
In emacs lisp:
(defun example (x) (list 'toplevel x))
--> example
(flet ((example (x) (if (oddp x) (list 'lexical 'example x) (example (1-
x)))))
(values (example 1)
(example 2)))
--> ((lexical example 1)
(lexical example 1))
is not what was expected from (require 'cl)... You could report a bug,
but again, if you really want Common Lisp semantics, it might be
better to use emacs-cl.
--
__Pascal Bourguignon__
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- Re: Expected behavior of CL special forms, 'labels' and 'flet', inside macros.,
Pascal J. Bourguignon <=