emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Code for cond*


From: Stefan Monnier
Subject: Re: Code for cond*
Date: Sat, 03 Feb 2024 01:09:26 -0500
User-agent: Gnus/5.13 (Gnus v5.13)

>   > As I said: in Pcase I moved some of the "built-in" patterns, such as the
>   > backquote, out of the core (using `pcase-defmacro` to define them
>   > instead), as a way to make sure that `pcase-defmacro` is indeed
>   > flexible enough.
>
> You're suggesting that I do this by exploring, but that's the hard
> way.  Harder than actually necessary -- since the real intention of a
> macro facility is for defining other kinds of pattern _given the ones
> that will be provided_.  It's comparable to looking for axioms for
> mathematics (or even just plane geometry) -- interesting, but there
> was no need for the rest of mathematics to wait for this to work.

What have it tried to implement using the macro facility you designed
for your patterns?  Have you tried to implement, say the `map` pattern
we have in `map.el` or the `cl-struct` pattern?

> I wouldn't want to use it without making it include the improvements
> I've designed into cond*, and I expect that `pcase-defmacro' is not
> capable of implementing constrained variables or `cdr-ignore'.

Your expectation is incorrect.

> That would require changing the pcase pattern code.

I don't think so.  The primitive patterns were carefully chosen so it
shouldn't be needed.  E.g.:

    (pcase-defmacro constrain (symbol exp) `(and ,symbol (guard ,exp)))

Admittedly, for `cdr-ignore` it would take more than a one-liner,
because it affects the interpretation of all the patterns within it
(which makes its meaning somewhat unclear: should `(constrain x (null
(cdr x)))` be ignored if it appears within a `cdr-ignore`?).
It might be the case that a clean implementation would require some
adjustments to the implementation of other patterns.  The details
would matter.

> If you tell me the name of the function in pcase which is the entry
> point for processing a pattern, with that starting point I might be
> able to understand some of that code.  I doubt it will change the
> situation, but I will take a look.

As I said, you don't need to know the internals, as shown in the
PoC below.  Which adds a `pcase*` construct to your `cond*`. It's used
like your `match*` but with Pcase patterns.
[ The patch also fixes some misuses of ";;; " which are reserved for
  sectioning and mess up `outline-minor-mode`.  ]

Also, BTW, I don't understand this behavior of your code:

    (macroexpand '(cond* ((match* `(c ,@d ,e) DAT) BRANCH1)))
==>
    (let ((d2624 DAT))
     (if (and (consp d2624) (eq 'c (car d2624)) (append (cdr d2624) (list e)))
         (let* ((d (cdr d2624))) BRANCH1)
       nil))


        Stefan


diff --git a/lisp/cond*.el b/lisp/cond*.el
index e40543ce393..d25bd858324 100644
--- a/lisp/cond*.el
+++ b/lisp/cond*.el
@@ -218,8 +218,8 @@ cond*-convert-condition
                    ;; Then always go on to run the UNCONDIT-CLAUSES.
                    (if true-exps
                        `(let ((,init-gensym ,first-value))
-;;; ??? Should we make the bindings a second time for the UNCONDIT-CLAUSES.
-;;; as the doc string says, for uniformity with match*?
+;;;  ??? Should we make the bindings a second time for the UNCONDIT-CLAUSES.
+;;;  as the doc string says, for uniformity with match*?
                           (let* ,mod-bindings
                             (when ,init-gensym
                               . ,true-exps)
@@ -235,6 +235,18 @@ cond*-convert-condition
                     (let* ,mod-bindings
                       (when ,init-gensym
                         . ,true-exps)))))))
+          ((eq pat-type 'pcase*)
+           (if true-exps
+               (progn
+                 (cl-assert (null uncondit-clauses))
+                 (cl-assert (or (null iffalse) rest))
+                 `(pcase ,(nth 2 condition)
+                    (,(nth 1 condition) ,@true-exps)
+                    (_ ,iffalse)))
+             (cl-assert (null iffalse))
+             (cl-assert (null rest))
+             `(pcase-let ((,(nth 1 condition) ,(nth 2 condition)))
+                (cond* . ,uncondit-clauses))))
           ((eq pat-type 'match*)
            (cond*-match condition true-exps uncondit-clauses iffalse))
           (t
@@ -340,8 +352,8 @@ cond*-bind-pattern-syms
 
 (defvar cond*-debug-pattern nil)
 
-;;; ??? Structure type patterns not implemented yet.
-;;; ??? Probably should optimize the `nth' calls in handling `list'.
+;;;  ??? Structure type patterns not implemented yet.
+;;;  ??? Probably should optimize the `nth' calls in handling `list'.
 
 (defun cond*-subpat (subpat cdr-ignore bindings inside-or backtrack-aliases 
data)
   "Generate code to match ibe subpattern within `match*'.




reply via email to

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