unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* Why is FUNC in cl-callf not allowed to be an expression?
@ 2019-05-09 21:52 Michael Heerdegen
  2019-05-10  0:47 ` Stefan Monnier
  0 siblings, 1 reply; 39+ messages in thread
From: Michael Heerdegen @ 2019-05-09 21:52 UTC (permalink / raw)
  To: Emacs Development

Hello,

I wonder why the FUNC argument in cl-callf is restricted to symbols (and
lambda expressions, though this is not documented).  I don't see any
reason to disallow arbitrary expressions, besides, maybe, that symbols
would become ambiguous.

I really would like to have an gv-callf that would simply interpret the
function argument as an expression.  cl-callf just saves the programmer
from typing the #' but forbids many use cases.

I think I would even like it most like this:

(defmacro gv-callf (call &optional n)
  (gv-letplace (_getter setter) (nth (or n 1) call)
    (funcall setter call)))

Example:

(let ((l (list 1 2)))
  (gv-callf (append l (list 3 4)))
  l)

=> (1 2 3 4)

(let ((l (list (list 'c 'd))))
  (gv-callf (append (list 'a 'b) (car l) (list 'e 'f)) 2)
  l)

=> ((a b c d e f))

That's simpler than current cl-callf, unites cl-callf and cl-callf2 in
something more general, and even eldoc still works in the CALL.


Michael.



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

* Re: Why is FUNC in cl-callf not allowed to be an expression?
  2019-05-09 21:52 Why is FUNC in cl-callf not allowed to be an expression? Michael Heerdegen
@ 2019-05-10  0:47 ` Stefan Monnier
  2019-05-10 11:32   ` Michael Heerdegen
  0 siblings, 1 reply; 39+ messages in thread
From: Stefan Monnier @ 2019-05-10  0:47 UTC (permalink / raw)
  To: emacs-devel

> I wonder why the FUNC argument in cl-callf is restricted to symbols (and
> lambda expressions, though this is not documented).  I don't see any
> reason to disallow arbitrary expressions, besides, maybe, that symbols
> would become ambiguous.

`callf` has been in cl.el "for ever" but it's not in Common-Lisp, so
I don't really know where it comes from.  I agree that when I moved it
to cl-lib, I missed an opportunity to fix it and make it take a normal
expression as first argument.

> I really would like to have an gv-callf that would simply interpret the
> function argument as an expression.  cl-callf just saves the programmer
> from typing the #' but forbids many use cases.

FWIW, you can circumvent this with

    (cl-flet ((f <EXPR>))
      (cl-callf f ...))

> I think I would even like it most like this:
>
> (defmacro gv-callf (call &optional n)
>   (gv-letplace (_getter setter) (nth (or n 1) call)
>     (funcall setter call)))

It's cute, tho I'm not too fond of specifying the place via a number,
personally,


        Stefan




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

* Re: Why is FUNC in cl-callf not allowed to be an expression?
  2019-05-10  0:47 ` Stefan Monnier
@ 2019-05-10 11:32   ` Michael Heerdegen
  2019-05-10 13:28     ` Stefan Monnier
  0 siblings, 1 reply; 39+ messages in thread
From: Michael Heerdegen @ 2019-05-10 11:32 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: emacs-devel

Stefan Monnier <monnier@iro.umontreal.ca> writes:

> > (defmacro gv-callf (call &optional n)
> >   (gv-letplace (_getter setter) (nth (or n 1) call)
> >     (funcall setter call)))
>
> It's cute, tho I'm not too fond of specifying the place via a number,
> personally,

[I should use GETTER btw for more efficient code:

(defmacro gv-callf (call &optional n)
  (unless n (setq n 1))
  (gv-letplace (getter setter) (nth n call)
    (setf (nth n call) getter)
    (funcall setter call)))
]

Yes, but still better than having it as part of the macro name as in
cl-callf2... I don't have any better idea currently.  We could still
extend cl-callf however.


Michael.



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

* Re: Why is FUNC in cl-callf not allowed to be an expression?
  2019-05-10 11:32   ` Michael Heerdegen
@ 2019-05-10 13:28     ` Stefan Monnier
  2019-05-10 14:19       ` Stefan Monnier
  0 siblings, 1 reply; 39+ messages in thread
From: Stefan Monnier @ 2019-05-10 13:28 UTC (permalink / raw)
  To: Michael Heerdegen; +Cc: emacs-devel

>> > (defmacro gv-callf (call &optional n)
>> >   (gv-letplace (_getter setter) (nth (or n 1) call)
>> >     (funcall setter call)))
>>
>> It's cute, tho I'm not too fond of specifying the place via a number,
>> personally,
>
> [I should use GETTER btw for more efficient code:
>
> (defmacro gv-callf (call &optional n)
>   (unless n (setq n 1))
>   (gv-letplace (getter setter) (nth n call)
>     (setf (nth n call) getter)
>     (funcall setter call)))
> ]
>
> Yes, but still better than having it as part of the macro name as in
> cl-callf2... I don't have any better idea currently.  We could still
> extend cl-callf however.

While it doesn't solve the problem, while playing with it I noticed that
I'm less annoyed by the use of a number if I can put it first, as in:

    (gv-callf 2
      (append head (car x) (cdr x)))
      
I'm not sure I can say why, tho.


        Stefan



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

* Re: Why is FUNC in cl-callf not allowed to be an expression?
  2019-05-10 13:28     ` Stefan Monnier
@ 2019-05-10 14:19       ` Stefan Monnier
  2019-05-10 14:22         ` Stefan Monnier
  0 siblings, 1 reply; 39+ messages in thread
From: Stefan Monnier @ 2019-05-10 14:19 UTC (permalink / raw)
  To: emacs-devel

> While it doesn't solve the problem, while playing with it I noticed that
> I'm less annoyed by the use of a number if I can put it first, as in:
>
>     (gv-callf 2
>       (append head (car x) (cdr x)))
>       
> I'm not sure I can say why, tho.

Now that I look at it again, I guess an "anamorphic" version would be
probably more obvious:

    (gv-modify (nth i l)
       (append head it (cdr x)))

Implementation left as an exercise for the reader,


        Stefan




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

* Re: Why is FUNC in cl-callf not allowed to be an expression?
  2019-05-10 14:19       ` Stefan Monnier
@ 2019-05-10 14:22         ` Stefan Monnier
  2019-05-10 15:18           ` Michael Heerdegen
  0 siblings, 1 reply; 39+ messages in thread
From: Stefan Monnier @ 2019-05-10 14:22 UTC (permalink / raw)
  To: emacs-devel

> Now that I look at it again, I guess an "anamorphic" version would be
> probably more obvious:
>
>     (gv-modify (nth i l)
>        (append head it (cdr x)))

And I see it solves another downside of (gv-callf N EXP), which is that in

    (gv-callf 2 (append HEAD (nth INDEX LIST) TAIL))
    
the evaluation order will actually end up being

    INDEX; LIST; HEAD; TAIL
    
which is counter-intuitive.


        Stefan




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

* Re: Why is FUNC in cl-callf not allowed to be an expression?
  2019-05-10 14:22         ` Stefan Monnier
@ 2019-05-10 15:18           ` Michael Heerdegen
  2019-05-13 16:47             ` Stefan Monnier
  0 siblings, 1 reply; 39+ messages in thread
From: Michael Heerdegen @ 2019-05-10 15:18 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: emacs-devel

Stefan Monnier <monnier@iro.umontreal.ca> writes:

> > Now that I look at it again, I guess an "anamorphic" version would be
> > probably more obvious:
> >
> >     (gv-modify (nth i l)
> >        (append head it (cdr x)))

I guess I would rather like it with explicit naming:

(defmacro gv-modify (binding call)
  (declare (indent 1))
  (pcase-let ((`(,var ,place) binding))
    (gv-letplace (getter setter) place
      (funcall setter `(let ((,var ,getter)) ,call)))))

Example:

(let ((l '(x ((2 3)))))
  (gv-modify (plc (car (cadr l)))
    (append '(0 1) plc '(4 5)))
  l)

=> (x ((0 1 2 3 4 5)))

> And I see it solves another downside of (gv-callf N EXP), which is that in
>
>     (gv-callf 2 (append HEAD (nth INDEX LIST) TAIL))
>
> the evaluation order will actually end up being
>
>     INDEX; LIST; HEAD; TAIL
>
> which is counter-intuitive.

The disadvantage is that the `append' call looks a bit pulled apart, but
I think it would be ok for me.


Michael.



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

* Re: Why is FUNC in cl-callf not allowed to be an expression?
  2019-05-10 15:18           ` Michael Heerdegen
@ 2019-05-13 16:47             ` Stefan Monnier
  2019-05-14 12:36               ` Michael Heerdegen
  2019-05-14 23:32               ` Michael Heerdegen
  0 siblings, 2 replies; 39+ messages in thread
From: Stefan Monnier @ 2019-05-13 16:47 UTC (permalink / raw)
  To: emacs-devel

> (defmacro gv-modify (binding call)

Why not (gv-modify VAR PLACE EXP) ?
I mean, is there any hope/possibility we'll ever want to extend
`binding` to anything else than "a single VAR and a single PLACE"?

Or do you actually like having the extra set of parens around the
VAR-PLACE pair?


        Stefan




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

* Re: Why is FUNC in cl-callf not allowed to be an expression?
  2019-05-13 16:47             ` Stefan Monnier
@ 2019-05-14 12:36               ` Michael Heerdegen
  2019-05-14 23:32               ` Michael Heerdegen
  1 sibling, 0 replies; 39+ messages in thread
From: Michael Heerdegen @ 2019-05-14 12:36 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: emacs-devel

Stefan Monnier <monnier@iro.umontreal.ca> writes:

> > (defmacro gv-modify (binding call)
>
> Why not (gv-modify VAR PLACE EXP) ?
> I mean, is there any hope/possibility we'll ever want to extend
> `binding` to anything else than "a single VAR and a single PLACE"?

Yeah - I was on a trip, and the first thing that occurred to my when I
was traveling was that these extra parens are nonsense.

Michael.



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

* Re: Why is FUNC in cl-callf not allowed to be an expression?
  2019-05-13 16:47             ` Stefan Monnier
  2019-05-14 12:36               ` Michael Heerdegen
@ 2019-05-14 23:32               ` Michael Heerdegen
  2019-05-15  2:02                 ` Stefan Monnier
  1 sibling, 1 reply; 39+ messages in thread
From: Michael Heerdegen @ 2019-05-14 23:32 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: emacs-devel

Stefan Monnier <monnier@iro.umontreal.ca> writes:

> > (defmacro gv-modify (binding call)

Here is another idea:

(defmacro gv-with-place (place f)
  (declare (indent 1))
  (gv-letplace (getter setter) place
    (let ((v (make-symbol "v")))
      `(funcall ,f ,getter (lambda (,v) ,(funcall setter v))))))

Example:

(let ((x '((a))))
  (gv-with-place (car x)
    (lambda (v set)
      (funcall set (append '(1 2) v '(3 4)))))
  x)

=> ((1 2 a 3 4))

The usage looks a bit longer than in all other proposals, but I find it
cleaner.  It's also more general, you can e.g. make setting conditional
as in your (commented) `gv-pushnew!'.  The second arg of `gv-with-place'
being a function also gives a chance for factoring.  More function calls
at run time involved, though.

I see that the suggestion comes near to just use `gv-letplace' in the
first place, but I think it's easier to understand for the end
programmer.


Michael.



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

* Re: Why is FUNC in cl-callf not allowed to be an expression?
  2019-05-14 23:32               ` Michael Heerdegen
@ 2019-05-15  2:02                 ` Stefan Monnier
  2019-05-15 16:38                   ` Michael Heerdegen
  2019-05-15 19:17                   ` Michael Heerdegen
  0 siblings, 2 replies; 39+ messages in thread
From: Stefan Monnier @ 2019-05-15  2:02 UTC (permalink / raw)
  To: Michael Heerdegen; +Cc: emacs-devel

> (defmacro gv-with-place (place f)
>   (declare (indent 1))
>   (gv-letplace (getter setter) place
>     (let ((v (make-symbol "v")))
>       `(funcall ,f ,getter (lambda (,v) ,(funcall setter v))))))

We could at least avoid the overall `funcall`:

    (defmacro gv-with-place (val setfun place &rest body)
      (declare (indent 3))
      (gv-letplace (getter setter) place
        `(let ((,val ,getter)
               (,setfun (lambda (v) ,(funcall setter 'v))))
           ,@body)))

Along the same lines maybe we could provide a (gv-ref VAL SETFUN) 
pcase-macro, so you could do

    (pcase-let (((gv-ref val setter) (gv-ref PLACE)))
      (unless (member X val) (funcall setter (cons X val))))

Even better would be if we could do

    (pcase-let (((gv-ref p) (gv-ref PLACE)))
      (unless (member X p) (setf p (cons X p))))

but it seems this would require non-trivial changes to pcase (since
basically `p` should not be bound there with a `let` but with
a `cl-symbol-macrolet`).

Still, I think the `gv-modify` discussed earlier hits a sweeter spot.


        Stefan



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

* Re: Why is FUNC in cl-callf not allowed to be an expression?
  2019-05-15  2:02                 ` Stefan Monnier
@ 2019-05-15 16:38                   ` Michael Heerdegen
  2019-05-15 17:19                     ` Michael Heerdegen
  2019-05-16 13:12                     ` Stefan Monnier
  2019-05-15 19:17                   ` Michael Heerdegen
  1 sibling, 2 replies; 39+ messages in thread
From: Michael Heerdegen @ 2019-05-15 16:38 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: emacs-devel

Stefan Monnier <monnier@IRO.UMontreal.CA> writes:

> > (defmacro gv-with-place (place f)
> >   (declare (indent 1))
> >   (gv-letplace (getter setter) place
> >     (let ((v (make-symbol "v")))
> >       `(funcall ,f ,getter (lambda (,v) ,(funcall setter v))))))
>
> We could at least avoid the overall `funcall`:
>
>     (defmacro gv-with-place (val setfun place &rest body)
>       (declare (indent 3))
>       (gv-letplace (getter setter) place
>         `(let ((,val ,getter)
>                (,setfun (lambda (v) ,(funcall setter 'v))))
>            ,@body)))

Yes, or maybe even

(defmacro gv-with-place (val-sym setfun-sym place &rest body)
  (declare (indent 3))
  (gv-letplace (getter setter) place
    (let ((v (make-symbol "v")))
      `(cl-flet ((,setfun-sym (lambda (,v) ,(funcall setter v))))
         (let ((,val-sym ,getter))
           ,@body)))))

Example:

  (let ((l '(2 3 4)))
    (gv-with-place p set (cdr l)
      (unless (memq 1 p)
        (set (cons 1 p))))
    l)

  ==> (2 1 3 4)

> Along the same lines maybe we could provide a (gv-ref VAL SETFUN)
> pcase-macro, so you could do
>
>     (pcase-let (((gv-ref val setter) (gv-ref PLACE)))
>       (unless (member X val) (funcall setter (cons X val))))
>
> Even better would be if we could do
>
>     (pcase-let (((gv-ref p) (gv-ref PLACE)))
>       (unless (member X p) (setf p (cons X p))))
>
> but it seems this would require non-trivial changes to pcase (since
> basically `p` should not be bound there with a `let` but with
> a `cl-symbol-macrolet`).

I tried to implement more or less that as a normal macro:

(defun gv-ad-hoc-place (val _setter)
  (declare (compiler-macro (lambda (_) val))
           (gv-expander funcall))
  val)

(defmacro gv-do-place (place-sym place &rest body)
  (declare (indent 2))
  (gv-letplace (getter setter) place
    `(let ((val ,getter))
       (cl-symbol-macrolet ((,place-sym (gv-ad-hoc-place val ,setter)))
         ,@body))))

Example:
  (let ((l '(2 3 4)))
    (gv-do-place p (cdr l)
      (unless (memq 1 p)
        (setf p (cons 1 p))))
    l)

  ==> (2 1 3 4)

Note that `gv-synthetic-place' can't be used here because in setf it
would just expand to (setq val ...) with val being the let-bound symbol
in the implementation, instead of something setf'ing the PLACE.

> Still, I think the `gv-modify` discussed earlier hits a sweeter spot.

Is it still your favorite?


Michael.



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

* Re: Why is FUNC in cl-callf not allowed to be an expression?
  2019-05-15 16:38                   ` Michael Heerdegen
@ 2019-05-15 17:19                     ` Michael Heerdegen
  2019-05-16  2:18                       ` Michael Heerdegen
  2019-05-16 13:12                     ` Stefan Monnier
  1 sibling, 1 reply; 39+ messages in thread
From: Michael Heerdegen @ 2019-05-15 17:19 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: emacs-devel

Michael Heerdegen <michael_heerdegen@web.de> writes:

> (defmacro gv-do-place (place-sym place &rest body)
>   (declare (indent 2))
>   (gv-letplace (getter setter) place
>     `(let ((val ,getter))
>        (cl-symbol-macrolet ((,place-sym (gv-ad-hoc-place val ,setter)))
>          ,@body))))

A better name for this might be "gv-place-let", though that could be
confused with "gv-letplace".

Michael.



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

* Re: Why is FUNC in cl-callf not allowed to be an expression?
  2019-05-15  2:02                 ` Stefan Monnier
  2019-05-15 16:38                   ` Michael Heerdegen
@ 2019-05-15 19:17                   ` Michael Heerdegen
  1 sibling, 0 replies; 39+ messages in thread
From: Michael Heerdegen @ 2019-05-15 19:17 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: emacs-devel

Stefan Monnier <monnier@IRO.UMontreal.CA> writes:

> Even better would be if we could do
>
>     (pcase-let (((gv-ref p) (gv-ref PLACE)))
>       (unless (member X p) (setf p (cons X p))))
>
> but it seems this would require non-trivial changes to pcase (since
> basically `p` should not be bound there with a `let` but with
> a `cl-symbol-macrolet`).

FWIW I'm all for enhancing pcase so that it can establish other types of
bindings in general.

Michael.



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

* Re: Why is FUNC in cl-callf not allowed to be an expression?
  2019-05-15 17:19                     ` Michael Heerdegen
@ 2019-05-16  2:18                       ` Michael Heerdegen
  0 siblings, 0 replies; 39+ messages in thread
From: Michael Heerdegen @ 2019-05-16  2:18 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: emacs-devel

Michael Heerdegen <michael_heerdegen@web.de> writes:

> A better name for this might be "gv-place-let", though that could be
> confused with "gv-letplace".

I played with it a bit.  It may make sense to make this "gv-place-let"
accept a binding list and implement a "gv-place-let*".  Here are two
examples where this would be useful:

(let ((x '(2 . 1)))
  (gv-place-let a (car x)
    (gv-place-let b (cdr x)
      (when (< b a) (cl-rotatef a b))))
  x)

==> (1 . 2)

(let ((l '(1 (2 3) 4)))
  (gv-place-let p1 (nth 1 l)
    (gv-place-let p2 (car p1)
      (setq p2 (list p2 (- p2)))))
  l)
==> (1 ((2 -2) 3) 4)


Michael.



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

* Re: Why is FUNC in cl-callf not allowed to be an expression?
  2019-05-15 16:38                   ` Michael Heerdegen
  2019-05-15 17:19                     ` Michael Heerdegen
@ 2019-05-16 13:12                     ` Stefan Monnier
  2019-05-16 14:37                       ` Michael Heerdegen
  1 sibling, 1 reply; 39+ messages in thread
From: Stefan Monnier @ 2019-05-16 13:12 UTC (permalink / raw)
  To: emacs-devel

> (defun gv-ad-hoc-place (val _setter)
>   (declare (compiler-macro (lambda (_) val))
>            (gv-expander funcall))
>   val)
[...]
> Note that `gv-synthetic-place' can't be used here because in setf it
> would just expand to (setq val ...) with val being the let-bound symbol
> in the implementation, instead of something setf'ing the PLACE.

Hmm... that's indeed what I see, but I haven't yet understood why that
is (or rather, why that doesn't happen to your gv-ad-hoc-place).
I guess that qualifies as a bug in gv-synthetic-place (not that it
matters too much: I can't find a single use of it).


        Stefan




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

* Re: Why is FUNC in cl-callf not allowed to be an expression?
  2019-05-16 13:12                     ` Stefan Monnier
@ 2019-05-16 14:37                       ` Michael Heerdegen
  2019-05-16 15:09                         ` Michael Heerdegen
  0 siblings, 1 reply; 39+ messages in thread
From: Michael Heerdegen @ 2019-05-16 14:37 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: emacs-devel

Stefan Monnier <monnier@iro.umontreal.ca> writes:

> Hmm... that's indeed what I see, but I haven't yet understood why that
> is (or rather, why that doesn't happen to your gv-ad-hoc-place).  I
> guess that qualifies as a bug in gv-synthetic-place (not that it
> matters too much: I can't find a single use of it).

Well, let's see:

;; works:
(let ((l '(0)))
  (cl-symbol-macrolet ((p (gv-synthetic-place (car l) (lambda (v) `(setcar l ,v)))))
    (setf p 1))
  l) ;; ==> (1)

;; dosn't work:
(let ((l '((0))))
  (let ((cl (car l)))
    (cl-symbol-macrolet ((p (gv-synthetic-place cl (lambda (v) `(setcar cl ,v)))))
      (setf p 1)))
  l) ;; ==> ((0))

;; but this works
(let ((l '((0))))
  (let ((cl (car l)))
    (setf (gv-synthetic-place cl (lambda (v) `(setcar cl ,v))) 1))
  l) ;; ((1))

The problem in the second case is that `cl-symbol-macrolet' is too
eager: it also macroexpands the symbol expansion `p' inside the `setf',
i.e. it expands the `gv-synthetic-place' macro call, to just `cl', so
you get (setf cl 1).

That just doesn't happen to my version since it's a function instead of
a macro (and the compiler macro seems to be applied later).

Any suggestions?


Michael.



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

* Re: Why is FUNC in cl-callf not allowed to be an expression?
  2019-05-16 14:37                       ` Michael Heerdegen
@ 2019-05-16 15:09                         ` Michael Heerdegen
  2019-05-16 19:34                           ` Stefan Monnier
  0 siblings, 1 reply; 39+ messages in thread
From: Michael Heerdegen @ 2019-05-16 15:09 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: emacs-devel

[-- Attachment #1: Type: text/plain, Size: 375 bytes --]

Michael Heerdegen <michael_heerdegen@web.de> writes:

> The problem in the second case is that `cl-symbol-macrolet' is too
> eager: it also macroexpands the symbol expansion `p' inside the `setf',
> i.e. it expands the `gv-synthetic-place' macro call, to just `cl', so
> you get (setf cl 1).

Something like this would help (i.e. gv-synthetic-place would
work as expected):


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-WIP-Small-fix-in-cl-sm-macroexpand.patch --]
[-- Type: text/x-diff, Size: 963 bytes --]

From e6c6e2a360e7970c8c687af580b0fcabc11aaae7 Mon Sep 17 00:00:00 2001
From: Michael Heerdegen <michael_heerdegen@web.de>
Date: Thu, 16 May 2019 17:05:07 +0200
Subject: [PATCH] WIP: Small fix in cl--sm-macroexpand

---
 lisp/emacs-lisp/cl-macs.el | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/lisp/emacs-lisp/cl-macs.el b/lisp/emacs-lisp/cl-macs.el
index 8af8fccde7..ce4be75d2b 100644
--- a/lisp/emacs-lisp/cl-macs.el
+++ b/lisp/emacs-lisp/cl-macs.el
@@ -2152,7 +2152,8 @@ cl--sm-macroexpand
              ;; Perform symbol-macro expansion.
              (let ((symval (assq exp venv)))
                (when symval
-                 (setq exp (cadr symval)))))
+                 (setq exp (cadr symval))
+                 nil)))
             (`(setq . ,_)
              ;; Convert setq to setf if required by symbol-macro expansion.
              (let* ((args (mapcar (lambda (f) (macroexpand f env))
--
2.20.1


[-- Attachment #3: Type: text/plain, Size: 131 bytes --]


but I have no clue if it's correct or a good idea.  Symbol macro
bindings to macro forms are rare in the Emacs sources.

Michael.

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

* Re: Why is FUNC in cl-callf not allowed to be an expression?
  2019-05-16 15:09                         ` Michael Heerdegen
@ 2019-05-16 19:34                           ` Stefan Monnier
  2019-05-16 21:46                             ` Michael Heerdegen
  0 siblings, 1 reply; 39+ messages in thread
From: Stefan Monnier @ 2019-05-16 19:34 UTC (permalink / raw)
  To: Michael Heerdegen; +Cc: emacs-devel

> Something like this would help (i.e. gv-synthetic-place would
> work as expected):
[...]
> but I have no clue if it's correct or a good idea.

It's not correct in general, no.  But it pointed me to the origin of the
problem.  I installed a fix.

This said, having `gv-expander` on a macro is always risky business
because it makes the result of macroexpansion sensitive to the order in
which things are expanded.  Of course, having both compiler-macro and
gv-expander suffers fundamentally from the same problem, tho to
a lesser extent.

Related to your patch, we should change `macroexpand` to call
`macroexpand-1` and then make `cl-symbol-macrolet` advise
`macroexpand-1` so it doesn't need the `while` loop.


        Stefan




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

* Re: Why is FUNC in cl-callf not allowed to be an expression?
  2019-05-16 19:34                           ` Stefan Monnier
@ 2019-05-16 21:46                             ` Michael Heerdegen
  2019-05-16 23:06                               ` Stefan Monnier
  0 siblings, 1 reply; 39+ messages in thread
From: Michael Heerdegen @ 2019-05-16 21:46 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: emacs-devel

Stefan Monnier <monnier@iro.umontreal.ca> writes:

> > Something like this would help (i.e. gv-synthetic-place would
> > work as expected):
> [...]
> > but I have no clue if it's correct or a good idea.
>
> It's not correct in general, no.  But it pointed me to the origin of the
> problem.  I installed a fix.

I had a hard time to understand why that works until I found that
(setf p ...) with symbol p symbol-macro bound is first expanded into
setq (treating p as a simple symbol) and that it treated by your fix
(and gets transformed into a setf again).  Ok, why not.

> Related to your patch, we should change `macroexpand` to call
> `macroexpand-1` and then make `cl-symbol-macrolet` advise
> `macroexpand-1` so it doesn't need the `while` loop.

Sounds reasonable, but I don't volunteer to do it.

What do think now about `gv-place-let'?  Does that look acceptable?

Thanks,

Michael.



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

* Re: Why is FUNC in cl-callf not allowed to be an expression?
  2019-05-16 21:46                             ` Michael Heerdegen
@ 2019-05-16 23:06                               ` Stefan Monnier
  2019-05-17 22:53                                 ` Michael Heerdegen
  0 siblings, 1 reply; 39+ messages in thread
From: Stefan Monnier @ 2019-05-16 23:06 UTC (permalink / raw)
  To: emacs-devel

> What do think now about `gv-place-let'?  Does that look acceptable?

The existence of both `gv-letplace` and `gv-place-let` is kind of
problematic for the occasional user who'll struggle to remember which
is which.

So I think it needs a name which clarifies the difference.


        Stefan




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

* Re: Why is FUNC in cl-callf not allowed to be an expression?
  2019-05-16 23:06                               ` Stefan Monnier
@ 2019-05-17 22:53                                 ` Michael Heerdegen
  2019-05-18 14:09                                   ` Stefan Monnier
  0 siblings, 1 reply; 39+ messages in thread
From: Michael Heerdegen @ 2019-05-17 22:53 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: emacs-devel

Stefan Monnier <monnier@iro.umontreal.ca> writes:

> So I think it needs a name which clarifies the difference.

Hmm, ok.  Here is a draft supporting multiple (parallel) bindings.  The
macro builds code by recursively calling `gv-letplace', the innermost
expression is one big symbol-macrolet that makes use of the bound
getters and setters.

#+begin_src emacs-lisp
(defmacro gv-place-bind (bindings &rest body)
  "Make place expression bindings.
BINDINGS is a list of elements of the form (VAR PLACE).

Eval BODY with...

The effect is very similar to `cl-symbol-macrolet'
but preferred for place expressions since it produces more
efficient code.

\(fn ((VAR PLACE) ...) FORM...)"
  (declare (indent 1))
  (letrec ((helper
            (lambda (bindings symbols+getters+setters body)
              (if bindings
                  (let ((binding (car bindings)))
                    (gv-letplace (getter setter) (cadr binding)
                      (funcall helper
                               (cdr bindings)
                               (cons (list (car binding) getter setter)
                                     symbols+getters+setters)
                               body)))
                `(cl-symbol-macrolet
                     ,(mapcar
                       (lambda (entry)
                         `(,(car entry)
                           (gv-synthetic-place ,(cadr entry) ,(caddr entry))))
                       (nreverse symbols+getters+setters))
                   ,@body)))))
    (funcall helper bindings '() body)))
#+end_src

;; Example:
(let ((l '(2 3 4)))
    (gv-place-bind ((p (cdr l)))
      (unless (memq 1 p)
        (setf p (cons 1 p))))
    l)
;; ==> (2 1 3 4)

Writing the docstring made me thoughtful though - how is this different
from symbol-macrolet?  An advantage is that it generates a bit more
efficient code for "complicated" (nested) place expressions.

OTOH, the purpose of symbol-macrolet is, at the end, more or less
defining abbreviations of place expressions.  So I wonder now if the
right thing to do is rather to improve symbol-macrolet instead to make
it generate better code by consulting getters and setters itself,
instead of blindly substituting.

My second point in this message: thinking once more about callf, we
could also support a syntax like (callf (with EXPR) PLACE ARG) or
something like that to support expressions as first arg.

Michael.



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

* Re: Why is FUNC in cl-callf not allowed to be an expression?
  2019-05-17 22:53                                 ` Michael Heerdegen
@ 2019-05-18 14:09                                   ` Stefan Monnier
  2019-05-20 23:25                                     ` Michael Heerdegen
                                                       ` (2 more replies)
  0 siblings, 3 replies; 39+ messages in thread
From: Stefan Monnier @ 2019-05-18 14:09 UTC (permalink / raw)
  To: Michael Heerdegen; +Cc: emacs-devel

> (defmacro gv-place-bind (bindings &rest body)

Hmm... "bind", eh?  I don't think that's different enough.
How 'bout something more like a "gv-alias"?

> Writing the docstring made me thoughtful though - how is this different
> from symbol-macrolet?

Indeed, they're closely related but symbol-macrolet does not "evaluates"
anything at the "binding" site.  Also it can also be used for purposes
different from "places", e.g. to keep a log of all the accessed to
a "variable" (tho, we could just as well create a (journaled PLACE)
pseudo place which would record accesses in the very same way).

Yeah, maybe a "place alias" is a generalization of symbol-macro.

Actually, no: symbol-macro can also expand to other macro-calls which
are supposed to be re-expanded at each use-site, AFAIK, so it can
macro-expand to something different every time the "variable" is
referenced, which is not the case of places, I think.

Maybe people over on comp.lang.lisp (or other Lisp discussion area)
would have some insight about this.

> My second point in this message: thinking once more about callf, we
> could also support a syntax like (callf (with EXPR) PLACE ARG) or
> something like that to support expressions as first arg.

You can already do that, except that `with` is spelled `lambda (it)`:

    (cl-callf (lambda (it) EXPR) PLACE)
  
Notice that the gv-callf we discussed are equivalent to the above rather
than to something where the EXPR is evaluated to decide which function
to call.  To me, the benefit of

    (gv-modify it PLACE EXPR)
    
[with or without the `it`] is that expressions appear in the order in
which they're evaluated, and also that it looks more like `setf`, which
is right since this is about doing a `setf` just with the added twist
that it can refer to the old value of the variable to compute the
new one.


        Stefan




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

* Re: Why is FUNC in cl-callf not allowed to be an expression?
  2019-05-18 14:09                                   ` Stefan Monnier
@ 2019-05-20 23:25                                     ` Michael Heerdegen
  2019-05-21  2:01                                       ` Stefan Monnier
  2019-05-22  1:00                                     ` Michael Heerdegen
  2019-05-27  0:20                                     ` Michael Heerdegen
  2 siblings, 1 reply; 39+ messages in thread
From: Michael Heerdegen @ 2019-05-20 23:25 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: emacs-devel

Stefan Monnier <monnier@iro.umontreal.ca> writes:

> > My second point in this message: thinking once more about callf, we
> > could also support a syntax like (callf (with EXPR) PLACE ARG) or
> > something like that to support expressions as first arg.
>
> You can already do that, except that `with` is spelled `lambda (it)`:
>
>     (cl-callf (lambda (it) EXPR) PLACE)

Sorry that I haven't been clear: I want EXPR to eval to the function to
be applied, not to the expression to set to.  Like in

  (cl-callf (with (if flag #'1+ #'1-)) my-number)

That's something I occasionally wanted.  Yes, I know I can paraphrase
this with cl-flet.  It's still disappointing that cl-callf can't do it
out of the box.


Michael.



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

* Re: Why is FUNC in cl-callf not allowed to be an expression?
  2019-05-20 23:25                                     ` Michael Heerdegen
@ 2019-05-21  2:01                                       ` Stefan Monnier
  2019-05-21  2:47                                         ` Michael Heerdegen
  2019-05-21  7:26                                         ` Andy Moreton
  0 siblings, 2 replies; 39+ messages in thread
From: Stefan Monnier @ 2019-05-21  2:01 UTC (permalink / raw)
  To: Michael Heerdegen; +Cc: emacs-devel

> Sorry that I haven't been clear: I want EXPR to eval to the function to
> be applied, not to the expression to set to.  Like in
>
>   (cl-callf (with (if flag #'1+ #'1-)) my-number)

Note that the gv-modify macro we discussed does not allow that either:
it doesn't funcall the result of an EXPR.

So, what you want can be written

    (cl-callf (lambda (x) (if flag (1+ x) (1- x))) my-number)
or
    (cl-callf (lambda (x) (funcall (if flag #'1+ #'1-) x)) my-number)

Just like you'd have to write

    (gv-modify my-number (if flag (1+ it) (1- it)))
or
    (gv-modify my-number (funcall (if flag #'1+ #'1-) it))


        Stefan




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

* Re: Why is FUNC in cl-callf not allowed to be an expression?
  2019-05-21  2:01                                       ` Stefan Monnier
@ 2019-05-21  2:47                                         ` Michael Heerdegen
  2019-05-21 10:16                                           ` Noam Postavsky
  2019-05-21 17:38                                           ` Stefan Monnier
  2019-05-21  7:26                                         ` Andy Moreton
  1 sibling, 2 replies; 39+ messages in thread
From: Michael Heerdegen @ 2019-05-21  2:47 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: emacs-devel

Stefan Monnier <monnier@iro.umontreal.ca> writes:

> >   (cl-callf (with (if flag #'1+ #'1-)) my-number)
>
> Note that the gv-modify macro we discussed does not allow that either:
> it doesn't funcall the result of an EXPR.

Yeah, I know.  But cl-callf already exists, and the first argument is
interpreted as a function, so would it hurt to remove the restriction to
fbound symbols?

OTOH, it probably wouldn't be good idea to complicate cl-callf if we
also want to add other stuff.

Would you want to see both gv-modify and gv-place-bind (or however we
call it) added?  I tend to be more a fan of gv-place-bind.

Michael.



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

* Re: Why is FUNC in cl-callf not allowed to be an expression?
  2019-05-21  2:01                                       ` Stefan Monnier
  2019-05-21  2:47                                         ` Michael Heerdegen
@ 2019-05-21  7:26                                         ` Andy Moreton
  2019-05-23 23:02                                           ` Michael Heerdegen
  1 sibling, 1 reply; 39+ messages in thread
From: Andy Moreton @ 2019-05-21  7:26 UTC (permalink / raw)
  To: emacs-devel

On Mon 20 May 2019, Stefan Monnier wrote:

>> Sorry that I haven't been clear: I want EXPR to eval to the function to
>> be applied, not to the expression to set to.  Like in
>>
>>   (cl-callf (with (if flag #'1+ #'1-)) my-number)
>
> Note that the gv-modify macro we discussed does not allow that either:
> it doesn't funcall the result of an EXPR.
>
> So, what you want can be written
>
>     (cl-callf (lambda (x) (if flag (1+ x) (1- x))) my-number)
> or
>     (cl-callf (lambda (x) (funcall (if flag #'1+ #'1-) x)) my-number)

The documentation for `cl-callf' says:

    Set PLACE to (FUNC PLACE ARGS...).
    FUNC should be an unquoted function name.  PLACE may be a symbol,
    or any generalized variable allowed by ‘setf’.

Please update this (and `cl-callf2') to show that FUNC can be a lambda.

Thanks,

    AndyM






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

* Re: Why is FUNC in cl-callf not allowed to be an expression?
  2019-05-21  2:47                                         ` Michael Heerdegen
@ 2019-05-21 10:16                                           ` Noam Postavsky
  2019-05-21 16:38                                             ` Michael Heerdegen
  2019-05-21 17:38                                           ` Stefan Monnier
  1 sibling, 1 reply; 39+ messages in thread
From: Noam Postavsky @ 2019-05-21 10:16 UTC (permalink / raw)
  To: Michael Heerdegen; +Cc: Stefan Monnier, Emacs developers

On Mon, 20 May 2019 at 22:47, Michael Heerdegen
<michael_heerdegen@web.de> wrote:

> > >   (cl-callf (with (if flag #'1+ #'1-)) my-number)

> OTOH, it probably wouldn't be good idea to complicate cl-callf if we
> also want to add other stuff.

Yeah, why not use something like

(funcallf (if flag #'1+ #'1-) my-number)



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

* Re: Why is FUNC in cl-callf not allowed to be an expression?
  2019-05-21 10:16                                           ` Noam Postavsky
@ 2019-05-21 16:38                                             ` Michael Heerdegen
  0 siblings, 0 replies; 39+ messages in thread
From: Michael Heerdegen @ 2019-05-21 16:38 UTC (permalink / raw)
  To: Noam Postavsky; +Cc: Stefan Monnier, Emacs developers

Noam Postavsky <npostavs@gmail.com> writes:

> > > >   (cl-callf (with (if flag #'1+ #'1-)) my-number)
>
> > OTOH, it probably wouldn't be good idea to complicate cl-callf if we
> > also want to add other stuff.
>
> Yeah, why not use something like
>
> (funcallf (if flag #'1+ #'1-) my-number)

FWIW, at least you can already write this as

  (cl-callf2 funcall (if flag #'1+ #'1-) my-number)

Michael.





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

* Re: Why is FUNC in cl-callf not allowed to be an expression?
  2019-05-21  2:47                                         ` Michael Heerdegen
  2019-05-21 10:16                                           ` Noam Postavsky
@ 2019-05-21 17:38                                           ` Stefan Monnier
  1 sibling, 0 replies; 39+ messages in thread
From: Stefan Monnier @ 2019-05-21 17:38 UTC (permalink / raw)
  To: Michael Heerdegen; +Cc: emacs-devel

> Yeah, I know.  But cl-callf already exists, and the first argument is
> interpreted as a function, so would it hurt to remove the restriction to
> fbound symbols?

FWIW, I don't care what happens to cl-callf ;-)
I just assume that

    (cl-callf (lambda (x) (funcall (if flag #'1+ #'1-) x)) my-number)
    
should compile to the same bytecode as

    (cl-callf (with (if flag #'1+ #'1-)) my-number)

I think the discussion whether the first arg can be an expression or
not is just an indication of a design problem in `cl-callf`.

IOW, I'm more interested in providing a better replacement than in
trying to extend it.

> Would you want to see both gv-modify and gv-place-bind (or however we
> call it) added?  I tend to be more a fan of gv-place-bind.

I don't really have a clear opinion formed on this.


        Stefan




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

* Re: Why is FUNC in cl-callf not allowed to be an expression?
  2019-05-18 14:09                                   ` Stefan Monnier
  2019-05-20 23:25                                     ` Michael Heerdegen
@ 2019-05-22  1:00                                     ` Michael Heerdegen
  2019-05-23  1:50                                       ` Michael Heerdegen
  2019-05-27  0:20                                     ` Michael Heerdegen
  2 siblings, 1 reply; 39+ messages in thread
From: Michael Heerdegen @ 2019-05-22  1:00 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: emacs-devel

Stefan Monnier <monnier@iro.umontreal.ca> writes:

> Yeah, maybe a "place alias" is a generalization of symbol-macro.
>
> Actually, no: [...]

I see Graham using symbol macros to abbreviate normal code in "On Lisp".
That's enough evidence for me not to touch symbol-macrolet.

> [...] symbol-macro can also expand to other macro-calls which are
> supposed to be re-expanded at each use-site, AFAIK, so it can
> macro-expand to something different every time the "variable" is
> referenced, which is not the case of places, I think.

With our current implementation of local macros, only the expansion
(compile) time matters, so this not so simple to do:

(let ((l '(0 1 2 3))
      (i '(0 1 2 3))
      (flag nil))
  (cl-macrolet ((yyy () (if flag '(nth 2 l) '(nth 3 i))))
    (cl-symbol-macrolet ((xxx (yyy)))
      (setf xxx 0)
      (list l i))))
|- void-variable: flag


(defvar flag t)

(defmacro zzz () (if flag '(nth 2 l) '(nth 3 i)))

(let ((l '(0 1 2 3))
      (i '(0 1 2 3))
      (flag nil))
  (cl-symbol-macrolet ((xxx (zzz)))
    (setf xxx 0)
    (list l i)))

==> ((0 1 2 3)
     (0 1 2 0)) ;; FLAG has been checked at expansion time

I could move the check of FLAG into the expansion, but that's not what
you meant, and since you made `if` forms place expressions, it would not
even be a counterexample any more.

Michael.



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

* Re: Why is FUNC in cl-callf not allowed to be an expression?
  2019-05-22  1:00                                     ` Michael Heerdegen
@ 2019-05-23  1:50                                       ` Michael Heerdegen
  2019-05-23  3:38                                         ` Stefan Monnier
  0 siblings, 1 reply; 39+ messages in thread
From: Michael Heerdegen @ 2019-05-23  1:50 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: emacs-devel

[-- Attachment #1: Type: text/plain, Size: 711 bytes --]

Michael Heerdegen <michael_heerdegen@web.de> writes:

> With our current implementation of local macros, only the expansion
> (compile) time matters, so this not so simple to do:
>
> (let ((l '(0 1 2 3))
>       (i '(0 1 2 3))
>       (flag nil))
>   (cl-macrolet ((yyy () (if flag '(nth 2 l) '(nth 3 i))))
>     (cl-symbol-macrolet ((xxx (yyy)))
>       (setf xxx 0)
>       (list l i))))
> |- void-variable: flag

Most Common Lisps seem to barf in this case (macro definition
referencing local variables).  I only found it explicitly described
here:

  http://www.lispworks.com/documentation/HyperSpec/Body/s_flet_.htm#macrolet

Anyway, I would like to speak out that one should not do that, how about
this?


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-doc-misc-cl.texi-Macro-Bindings-State-expansion-time.patch --]
[-- Type: text/x-diff, Size: 768 bytes --]

From ae8e42cf23e4883aed0177aad30d56f0e3e5086b Mon Sep 17 00:00:00 2001
From: Michael Heerdegen <michael_heerdegen@web.de>
Date: Thu, 23 May 2019 03:33:04 +0200
Subject: [PATCH] * doc/misc/cl.texi (Macro Bindings): State expansion time

---
 doc/misc/cl.texi | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/doc/misc/cl.texi b/doc/misc/cl.texi
index eb06791ba9..c96b9b6c3e 100644
--- a/doc/misc/cl.texi
+++ b/doc/misc/cl.texi
@@ -1360,6 +1360,8 @@ Macro Bindings
 affect only calls that appear physically within the body
 @var{forms}, possibly after expansion of other macros in the
 body.
+
+Like global macros local macros are expanded at compile-time.
 @end defmac

 @defmac cl-symbol-macrolet (bindings@dots{}) forms@dots{}
--
2.20.1


[-- Attachment #3: Type: text/plain, Size: 11 bytes --]



Michael.

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

* Re: Why is FUNC in cl-callf not allowed to be an expression?
  2019-05-23  1:50                                       ` Michael Heerdegen
@ 2019-05-23  3:38                                         ` Stefan Monnier
  2019-05-23 23:38                                           ` Michael Heerdegen
  0 siblings, 1 reply; 39+ messages in thread
From: Stefan Monnier @ 2019-05-23  3:38 UTC (permalink / raw)
  To: Michael Heerdegen; +Cc: emacs-devel

> @@ -1360,6 +1360,8 @@ Macro Bindings
>  affect only calls that appear physically within the body
>  @var{forms}, possibly after expansion of other macros in the
>  body.
> +
> +Like global macros local macros are expanded at compile-time.
>  @end defmac

Of course, if you don't compile the code, there's no "compile-time", so
this description becomes a bit weird.

Macros can be expanded at any time before executing the code, so indeed
they can't reliably make use of variables bound in the code surrounding
the macro call.  Whether they're local or global macros makes no
difference in this respect.

In practice, you basically can't compile code without first expanding
the macros it invokes, so when the code is compiled, the macros are
usually expanded at that time.


        Stefan




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

* Re: Why is FUNC in cl-callf not allowed to be an expression?
  2019-05-21  7:26                                         ` Andy Moreton
@ 2019-05-23 23:02                                           ` Michael Heerdegen
  0 siblings, 0 replies; 39+ messages in thread
From: Michael Heerdegen @ 2019-05-23 23:02 UTC (permalink / raw)
  To: Andy Moreton; +Cc: emacs-devel

Andy Moreton <andrewjmoreton@gmail.com> writes:

> The documentation for `cl-callf' says:
>
>     Set PLACE to (FUNC PLACE ARGS...).
>     FUNC should be an unquoted function name.  PLACE may be a symbol,
>     or any generalized variable allowed by ‘setf’.
>
> Please update this (and `cl-callf2') to show that FUNC can be a lambda.

Done in a564d6e8bb (master).  I didn't touch cl-callf2 because its
docstring only relegates to that of cl-callf.

The manual already lists all cases.  Actually it also explicitly
mentions macro names.  I guess I should add that to the doc string as
well?

Michael.



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

* Re: Why is FUNC in cl-callf not allowed to be an expression?
  2019-05-23  3:38                                         ` Stefan Monnier
@ 2019-05-23 23:38                                           ` Michael Heerdegen
  2019-05-24 15:29                                             ` Stefan Monnier
  0 siblings, 1 reply; 39+ messages in thread
From: Michael Heerdegen @ 2019-05-23 23:38 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: emacs-devel

Stefan Monnier <monnier@iro.umontreal.ca> writes:

> Macros can be expanded at any time before executing the code, so indeed
> they can't reliably make use of variables bound in the code surrounding
> the macro call.  Whether they're local or global macros makes no
> difference in this respect.

I would like to speak that out somewhere because it's not obvious, and
also explicitly for local macros (because the current docstring saying
"This is like `cl-flet'[...]" somehow made me think that they might be
different from global macros in this regard).

Can we say that macros are "expanded in the global environment", or
should we just say that the expander functions are not allowed to refer
to local variables (though, that would still leave some questions open,
e.g. what about local (flet-bound) local functions or other local
macros?).

My patch spoke about when these macros are expanded because of such
subtleties, I thought it could be better to imagine with that wording.


Michael.



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

* Re: Why is FUNC in cl-callf not allowed to be an expression?
  2019-05-23 23:38                                           ` Michael Heerdegen
@ 2019-05-24 15:29                                             ` Stefan Monnier
  2019-05-28 19:54                                               ` Michael Heerdegen
  0 siblings, 1 reply; 39+ messages in thread
From: Stefan Monnier @ 2019-05-24 15:29 UTC (permalink / raw)
  To: Michael Heerdegen; +Cc: emacs-devel

> I would like to speak that out somewhere because it's not obvious, and

Agreed.

> also explicitly for local macros (because the current docstring saying

I don't see them as any different, but clearly some users don't see it
this way, so we can put a reminder there, indeed.

> Can we say that macros are "expanded in the global environment", or

Sounds good.

> should we just say that the expander functions are not allowed to refer
> to local variables (though, that would still leave some questions open,
> e.g. what about local (flet-bound) local functions or other local
> macros?).

Something like it, yes (using "refer" can be tricky because they can
emit code which then refers to it, and this can be seen as "the macro
refers to" even though technically it's different).

> My patch spoke about when these macros are expanded because of such
> subtleties, I thought it could be better to imagine with that wording.

In macros.texi (@node Compiling Macros) as well as in loading.texi
(@cindex eager macro expansion) we allude to when macros are expanded,
but I think we should be more upfront about it somewhere.

A separate @node about when macro expansion can take place and what
environment it can rely on would be welcome.


        Stefan




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

* Re: Why is FUNC in cl-callf not allowed to be an expression?
  2019-05-18 14:09                                   ` Stefan Monnier
  2019-05-20 23:25                                     ` Michael Heerdegen
  2019-05-22  1:00                                     ` Michael Heerdegen
@ 2019-05-27  0:20                                     ` Michael Heerdegen
  2019-05-29 17:02                                       ` Stefan Monnier
  2 siblings, 1 reply; 39+ messages in thread
From: Michael Heerdegen @ 2019-05-27  0:20 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: emacs-devel

Stefan Monnier <monnier@iro.umontreal.ca> writes:

> Indeed, they're closely related but symbol-macrolet does not "evaluates"
> anything at the "binding" site.  Also it can also be used for purposes
> different from "places", e.g. to keep a log of all the accessed to
> a "variable" (tho, we could just as well create a (journaled PLACE)
> pseudo place which would record accesses in the very same way).

I also come to the conclusion that symbol-macrolet and place binding are
two different things.

E.g. in

(macroexpand-all
 '(gv-place-bind ((p (car (cdr x))))
    (progn (cl-incf p) p)))

==>
 (let*
    ((#1=#:v
      (cdr x)))
  (progn
    (setcar #1#
            (1+ #2=(car #1#)))
    #2#))

we want that the (cdr x) "calculation" is factored out because it is
always the same (an "inner place" reference so to say).

OTOH, `symbol-macrolet' might be used for arbitrary calculations.  It
would be surprising (wrong) if in

(symbol-macrolet ((r (list (random))))
  (list r r))

the `random' function would be called only once.

One can't reliably guess from the bound expression which case the coder
wants, so I'll leave s-macrolet as is.

Michael.



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

* Re: Why is FUNC in cl-callf not allowed to be an expression?
  2019-05-24 15:29                                             ` Stefan Monnier
@ 2019-05-28 19:54                                               ` Michael Heerdegen
  0 siblings, 0 replies; 39+ messages in thread
From: Michael Heerdegen @ 2019-05-28 19:54 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: emacs-devel

[-- Attachment #1: Type: text/plain, Size: 164 bytes --]

Stefan Monnier <monnier@iro.umontreal.ca> writes:

> > Can we say that macros are "expanded in the global environment", or
>
> Sounds good.

Ok, I installed this:


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-doc-misc-cl.texi-Macro-Bindings-Add-a-detail.patch --]
[-- Type: text/x-diff, Size: 935 bytes --]

From 997ac9f829059bf37c81fd586910c834394951e6 Mon Sep 17 00:00:00 2001
From: Michael Heerdegen <michael_heerdegen@web.de>
Date: Thu, 23 May 2019 03:33:04 +0200
Subject: [PATCH] * doc/misc/cl.texi (Macro Bindings): Add a detail

Say that calls of 'cl-macrolet' bound macros are expanded in the
global environment.
---
 doc/misc/cl.texi | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/doc/misc/cl.texi b/doc/misc/cl.texi
index eb06791ba9..ee73c65b78 100644
--- a/doc/misc/cl.texi
+++ b/doc/misc/cl.texi
@@ -1359,7 +1359,8 @@ Macro Bindings
 scoped.  The @code{cl-macrolet} binding will
 affect only calls that appear physically within the body
 @var{forms}, possibly after expansion of other macros in the
-body.
+body.  Calls of @code{cl-macrolet} bound macros are expanded in the
+global environment.
 @end defmac

 @defmac cl-symbol-macrolet (bindings@dots{}) forms@dots{}
--
2.20.1


[-- Attachment #3: Type: text/plain, Size: 215 bytes --]


> A separate @node about when macro expansion can take place and what
> environment it can rely on would be welcome.

That would be good, yes, though, I will probably not be the one writing
it.


Thanks,

Michael.

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

* Re: Why is FUNC in cl-callf not allowed to be an expression?
  2019-05-27  0:20                                     ` Michael Heerdegen
@ 2019-05-29 17:02                                       ` Stefan Monnier
  0 siblings, 0 replies; 39+ messages in thread
From: Stefan Monnier @ 2019-05-29 17:02 UTC (permalink / raw)
  To: emacs-devel

>> Indeed, they're closely related but symbol-macrolet does not "evaluates"
>> anything at the "binding" site.  Also it can also be used for purposes
>> different from "places", e.g. to keep a log of all the accessed to
>> a "variable" (tho, we could just as well create a (journaled PLACE)
>> pseudo place which would record accesses in the very same way).
>
> I also come to the conclusion that symbol-macrolet and place binding are
> two different things.

Right.  I think you can always use one to implement the functionality of
the other, but they're different.

> OTOH, `symbol-macrolet' might be used for arbitrary calculations.  It
> would be surprising (wrong) if in
>
>     (symbol-macrolet ((r (list (random))))
>       (list r r))
>
> the `random' function would be called only once.

Indeed, with gv-place-bind you'd need to use something like

    (gv-place-bind ((r (gv-cbn (list (random)))))
      (list r r))

for some definition of `gv-cbn` such as

    (defun gv-cbn (x)
      (declare (gv-expander (lambda (do)
                 (funcall do x (lambda (v) `(setf ,x ,v))))))
      x)


-- Stefan




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

end of thread, other threads:[~2019-05-29 17:02 UTC | newest]

Thread overview: 39+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-05-09 21:52 Why is FUNC in cl-callf not allowed to be an expression? Michael Heerdegen
2019-05-10  0:47 ` Stefan Monnier
2019-05-10 11:32   ` Michael Heerdegen
2019-05-10 13:28     ` Stefan Monnier
2019-05-10 14:19       ` Stefan Monnier
2019-05-10 14:22         ` Stefan Monnier
2019-05-10 15:18           ` Michael Heerdegen
2019-05-13 16:47             ` Stefan Monnier
2019-05-14 12:36               ` Michael Heerdegen
2019-05-14 23:32               ` Michael Heerdegen
2019-05-15  2:02                 ` Stefan Monnier
2019-05-15 16:38                   ` Michael Heerdegen
2019-05-15 17:19                     ` Michael Heerdegen
2019-05-16  2:18                       ` Michael Heerdegen
2019-05-16 13:12                     ` Stefan Monnier
2019-05-16 14:37                       ` Michael Heerdegen
2019-05-16 15:09                         ` Michael Heerdegen
2019-05-16 19:34                           ` Stefan Monnier
2019-05-16 21:46                             ` Michael Heerdegen
2019-05-16 23:06                               ` Stefan Monnier
2019-05-17 22:53                                 ` Michael Heerdegen
2019-05-18 14:09                                   ` Stefan Monnier
2019-05-20 23:25                                     ` Michael Heerdegen
2019-05-21  2:01                                       ` Stefan Monnier
2019-05-21  2:47                                         ` Michael Heerdegen
2019-05-21 10:16                                           ` Noam Postavsky
2019-05-21 16:38                                             ` Michael Heerdegen
2019-05-21 17:38                                           ` Stefan Monnier
2019-05-21  7:26                                         ` Andy Moreton
2019-05-23 23:02                                           ` Michael Heerdegen
2019-05-22  1:00                                     ` Michael Heerdegen
2019-05-23  1:50                                       ` Michael Heerdegen
2019-05-23  3:38                                         ` Stefan Monnier
2019-05-23 23:38                                           ` Michael Heerdegen
2019-05-24 15:29                                             ` Stefan Monnier
2019-05-28 19:54                                               ` Michael Heerdegen
2019-05-27  0:20                                     ` Michael Heerdegen
2019-05-29 17:02                                       ` Stefan Monnier
2019-05-15 19:17                   ` Michael Heerdegen

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

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