help-gnu-emacs
[Top][All Lists]
Advanced

[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__


reply via email to

[Prev in Thread] Current Thread [Next in Thread]