unofficial mirror of help-gnu-emacs@gnu.org
 help / color / mirror / Atom feed
* Expected behavior of CL special forms, 'labels' and 'flet', inside macros.
@ 2009-08-03  8:04 Jon Strait
  0 siblings, 0 replies; 2+ messages in thread
From: Jon Strait @ 2009-08-03  8:04 UTC (permalink / raw)
  To: help-gnu-emacs

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:

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

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

(map-chain '(7 8 9) (lambda (x) (* x 10)) (lambda (y) (+ y 4)))


I'm currently using Emacs 23.0.92

Thanks,
Jon





^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: Expected behavior of CL special forms, 'labels' and 'flet', inside macros.
       [not found] <mailman.3797.1249343677.2239.help-gnu-emacs@gnu.org>
@ 2009-08-04  1:49 ` Pascal J. Bourguignon
  0 siblings, 0 replies; 2+ messages in thread
From: Pascal J. Bourguignon @ 2009-08-04  1:49 UTC (permalink / raw)
  To: help-gnu-emacs

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__


^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2009-08-04  1:49 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-08-03  8:04 Expected behavior of CL special forms, 'labels' and 'flet', inside macros Jon Strait
     [not found] <mailman.3797.1249343677.2239.help-gnu-emacs@gnu.org>
2009-08-04  1:49 ` Pascal J. Bourguignon

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).