unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
From: akater <nuclearspace@gmail.com>
To: Stefan Monnier <monnier@iro.umontreal.ca>
Cc: emacs-devel@gnu.org
Subject: Re: [PATCH] Some improvements for cl-flet
Date: Wed, 03 Nov 2021 12:59:56 +0000	[thread overview]
Message-ID: <87h7ctqtrn.fsf@gmail.com> (raw)
In-Reply-To: <jwvily8btls.fsf-monnier+emacs@gnu.org>


[-- Attachment #1.1: Type: text/plain, Size: 2198 bytes --]

Sorry it took so long; Emacs build broke several times, an on top of
that Org is having some tectonic changes as well, and I've had my own
time trouble.

I tried the following patch.

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

> But that's a very minor cosmetic detail.  Either way works, I was just
> curious why you did it this way.
>
>
>         Stefan
>
>
> diff --git a/lisp/emacs-lisp/cl-macs.el b/lisp/emacs-lisp/cl-macs.el
> index 1852471bcbb..ad0477e3b68 100644
> --- a/lisp/emacs-lisp/cl-macs.el
> +++ b/lisp/emacs-lisp/cl-macs.el
> @@ -2030,7 +2030,10 @@ cl-flet
>    (let ((binds ()) (newenv macroexpand-all-environment))
>      (dolist (binding bindings)
>        (let ((var (make-symbol (format "--cl-%s--" (car binding))))
> +            (fname (car binding))
>              (args-and-body (cdr binding)))
> +        (if (eq (car-safe fname) 'setf)
> +            (setq fname (gv-setter (cadr fname))))
>          (if (and (= (length args-and-body) 1) (symbolp (car args-and-body)))
>              ;; Optimize (cl-flet ((fun var)) body).
>              (setq var (car args-and-body))
> @@ -2038,7 +2041,7 @@ cl-flet
>                                (car args-and-body)
>                              `(cl-function (lambda . ,args-and-body))))
>                  binds))
> -	(push (cons (car binding)
> +	(push (cons fname
>                      (lambda (&rest args)
>                        (if (eq (car args) cl--labels-magic)
>                            (list cl--labels-magic var)

Four of my tests failed which did pass for the solution I've proposed.

The first case is not even supported with global functions in Elisp so
I'm not sure how relevant it is.

Here are the summaries; the rest (results vs expected, some comments) is
attached.  I've received some complaints about my usage of Org markup in
the mailing list so details are omitted from the mail body.

** TEST-FAILED setf with #'(setf ..) in body
** TEST-FAILED non-setf local function within (setf ..) local function
** TEST-FAILED Local setf function within local non-setf function within local setf function
** TEST-FAILED Eponymous local macro, local function and its setf, local macro, local function


[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 865 bytes --]

[-- Attachment #2: Failed tests for gv-setter-based implementation of local setfs --]
[-- Type: text/plain, Size: 5434 bytes --]

#+title: Improving cl-flet in Emacs 29: Local setf solution by Stefan Monnier
#+author: =#<PERSON akater A24961DE3ADD04E057ADCF4599555CE6F2E1B21D>=
#+property: header-args :lexical t
#+startup: nologdone show2levels
#+todo: TEST-FAILED(f) | TEST-PASSED(p)

* Definition
#+begin_src emacs-lisp :results none
(defmacro cl-flet (bindings &rest body)
  "Make local function definitions.
Each definition can take the form (FUNC EXP) where
FUNC is the function name, and EXP is an expression that returns the
function value to which it should be bound, or it can take the more common
form (FUNC ARGLIST BODY...) which is a shorthand
for (FUNC (lambda ARGLIST BODY)).

FUNC is defined only within FORM, not BODY, so you can't write
recursive function definitions.  Use `cl-labels' for that.  See
info node `(cl) Function Bindings' for details.

\(fn ((FUNC ARGLIST BODY...) ...) FORM...)"
  (declare (indent 1)
           (debug ((&rest [&or (&define name function-form) (cl-defun)])
                   cl-declarations body)))
  (let ((binds ()) (newenv macroexpand-all-environment))
    (dolist (binding bindings)
      (let ((var (make-symbol (format "--cl-%s--" (car binding))))
            (fname (car binding))
            (args-and-body (cdr binding)))
        (if (eq 'setf (car-safe fname))
            (setq fname (gv-setter (cadr fname))))
        (if (and (= (length args-and-body) 1) (symbolp (car args-and-body)))
            ;; Optimize (cl-flet ((fun var)) body).
            (setq var (car args-and-body))
          (push (list var (if (= (length args-and-body) 1)
                              (car args-and-body)
                            `(cl-function (lambda . ,args-and-body))))
                binds))
	(push (cons fname
                    (lambda (&rest args)
                      (if (eq (car args) cl--labels-magic)
                          (list cl--labels-magic var)
                        `(funcall ,var ,@args))))
              newenv)))
    ;; FIXME: Eliminate those functions which aren't referenced.
    (macroexp-let* (nreverse binds)
                   (macroexpand-all
                    `(progn ,@body)
                    ;; Don't override lexical-let's macro-expander.
                    (if (assq 'function newenv) newenv
                      (cons (cons 'function #'cl--labels-convert) newenv))))))
#+end_src

* Tests
** TEST-FAILED setf with #'(setf ..) in body
The difference in ~(let ((setf-arg-0 t)) ..)~ is irrelevant, what's relevant is, ~#'(setf kar)~ is not recognized.
#+begin_src emacs-lisp :tangle no :results code :wrap example emacs-lisp
(macroexpand-1
 `(cl-flet (((setf kar) (new) 'just-an-example))
    (setf (kar) t)
    (funcall #'(setf kar) t)))
#+end_src

#+RESULTS:
#+begin_example emacs-lisp
(let*
    ((--cl-\(setf\ kar\)--
      (cl-function
       (lambda
         (new)
         'just-an-example))))
  (progn
    (funcall --cl-\(setf\ kar\)-- t)
    (funcall
     #'(setf kar)
     t)))
#+end_example

#+EXPECTED:
#+begin_example emacs-lisp
(let*
    ((--cl-\(setf\ kar\)--
      (cl-function
       (lambda
         (new)
         'just-an-example))))
  (progn
    (let
        ((setf-arg-0 t))
      (funcall --cl-\(setf\ kar\)-- setf-arg-0))
    (funcall --cl-\(setf\ kar\)-- t)))
#+end_example

** TEST-FAILED non-setf local function within (setf ..) local function
#+begin_src emacs-lisp :tangle no :results code :wrap example emacs-lisp
(condition-case err
    (let ((x (cons (cons nil nil) nil)))
      (cl-flet ((kar (x) (car x))
                ((setf kar) (new cons) (setf (car cons) new)))
        (setf (kar (kar x)) t))
      x)
  (t err))
#+end_src

#+RESULTS:
#+begin_example emacs-lisp
(void-function \(setf\ funcall\))
#+end_example

#+EXPECTED:
#+begin_example emacs-lisp
((t))
#+end_example

** TEST-FAILED Local setf function within local non-setf function within local setf function
#+begin_src emacs-lisp :tangle no :results code :wrap example emacs-lisp
(condition-case err
    (let ((x (cons (cons nil nil) nil))
          (y (cons (cons nil nil) nil)))
      (cl-flet ((kar (x) (car x))
                ((setf kar) (new cons) (setf (car cons) new)))
        (setf (kar (kar (setf (kar y) x))) t))
      (cl-values x y))
  (t err))
#+end_src

#+RESULTS:
#+begin_example emacs-lisp
(void-function \(setf\ funcall\))
#+end_example

#+EXPECTED:
#+begin_example emacs-lisp
(((t))
 (((t))))
#+end_example

** TEST-FAILED Eponymous local macro, local function and its setf, local macro, local function
#+begin_src emacs-lisp :tangle no :results code :wrap example emacs-lisp
(condition-case err
    (let (result)
      (cl-macrolet ((f (x) ``(f1 ,,x)))
        (push (f 0) result)
        (cl-flet ((f (x) `(f2 ,x))
        ((setf f) (new x) (f (list x new))))
          (push (f 1) result)
          (push (setf (f (f (setf (f 2) 3))) (f 4)) result)
          (cl-macrolet ((f (x) `(car (list `(f3 ,,x)))))
            (push (f 5) result)
            (push (setf (f (f (f 6))) (f 8)) result)
            (cl-flet ((f (x) `(f4 ,x)))
              (push (f 9) result)
              (push (setf (f (f (setf (f 10) 11))) (f 12)) result)))))
      result)
  (t err))
#+end_src

#+RESULTS:
#+begin_example emacs-lisp
(void-function \(setf\ funcall\))
#+end_example

#+EXPECTED:
#+begin_example emacs-lisp
((f1
  ((f4
    (f1
     (10 11)))
   (f4 12)))
 (f4 9)
 (f3 8)
 (f3 5)
 (f1
  ((f2
    (f1
     (2 3)))
   (f2 4)))
 (f2 1)
 (f1 0))
#+end_example

  reply	other threads:[~2021-11-03 12:59 UTC|newest]

Thread overview: 42+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-09-11 12:51 Some improvements for cl-flet akater
2021-09-11 23:32 ` Michael Heerdegen
2021-09-12  3:35   ` akater
2021-09-12 15:38     ` Stefan Monnier
2021-09-13  0:14     ` Michael Heerdegen
2021-09-13  2:26       ` Stefan Monnier
2021-10-07  2:32       ` akater
2021-10-07 18:03         ` Stefan Monnier
2021-10-08 21:57           ` Richard Stallman
2021-10-09  5:23             ` akater
2021-10-09  6:01               ` Michael Heerdegen
2021-10-09 23:37                 ` Richard Stallman
2021-10-10 10:41                   ` Po Lu
2021-10-10 20:27                     ` João Távora
2021-10-10 21:57                       ` Stefan Monnier
2021-10-11  0:45                       ` [External] : " Drew Adams
2021-10-11 21:16                     ` Richard Stallman
2021-10-11 21:26                       ` João Távora
2021-10-12 22:42                         ` Richard Stallman
2021-10-12  0:05                       ` Po Lu
2021-10-12  0:29                       ` Robin Tarsiger
2021-10-12 22:43                         ` Richard Stallman
2021-10-09 23:33               ` Richard Stallman
2021-10-09 23:33               ` Richard Stallman
2021-10-14  4:00               ` Michael Heerdegen
2021-09-23 22:37 ` [PATCH] " akater
2021-09-23 22:41   ` akater
2021-09-24  7:11     ` João Távora
2021-09-24 15:20       ` [PATCH] Some improvements for cl-flet, and some more akater
2021-09-24 16:22         ` João Távora
2021-09-25  1:28         ` Lars Ingebrigtsen
2021-09-25  8:37           ` João Távora
2021-09-24 20:30     ` [PATCH] Some improvements for cl-flet akater
2021-09-26  6:54     ` Lars Ingebrigtsen
2021-09-26 12:04       ` akater
2021-09-26 12:36         ` Lars Ingebrigtsen
2021-10-03  3:51     ` Stefan Monnier
2021-10-07  5:02       ` akater
2021-10-07 18:23         ` Stefan Monnier
2021-11-03 12:59           ` akater [this message]
2021-11-09 20:37             ` Stefan Monnier
2021-10-09  5:33       ` akater

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/emacs/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87h7ctqtrn.fsf@gmail.com \
    --to=nuclearspace@gmail.com \
    --cc=emacs-devel@gnu.org \
    --cc=monnier@iro.umontreal.ca \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).