emacs-devel
[Top][All Lists]
Advanced

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

Re: Instead of pcase


From: Dmitry Gutov
Subject: Re: Instead of pcase
Date: Mon, 20 Nov 2023 03:15:09 +0200
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Thunderbird/102.13.0

On 19/11/2023 23:15, Barry Fishman wrote:

Haskell is notable for using the same (or similar) syntax for
destructuring as it uses for constructing expressions.

pcase actually follows that practice with backquotes and commas.

Really?  I thought back-quoting was used (as an alternative way) to
construct nested lists, to express more simply the piecing together and
concatenating nested list pieces, particularly in macroes, and its
expansion at compile time is fairly obvious.

I guess what pcase is trying to do is the similar,

The reverse, to be more exact.

but it is expressing
something that, to me, seem far more complex to use.

I don't blame you, FWIW. But I've yet to see a "simpler" solution which would provide comparable functionality.

Its also mixing "destructuring" and "guard"s, all in one "super" domain
specific language.

Like loop, it can be powerful, but intimidating to people that don't use
it a lot.  But its usefulness to those that know it, encourages its
use in the code base.

But exiting Lisp destructuring via destructuring-bind and lambda
arguments, don't use backquoting.
They also don't provide any pattern matching of case-like functionality.

When you don't need a way to distinguish literals from variables, (un)quoting is indeed not needed.

One thing I did change was to reverse the defmethod style of (variable
type) to (type variable) to try to simplify recursion in the typeproto
syntax.

And in both matching and destructuring are done in the same expression
(the presence of the latter is determined by whether a pattern
contains variable bindindgs).

If x is a list with its first element a string "foo" and the second an
integer, remove it from x and add the second element to total:
    (proto-case x
      ((list* (string name) (integer count) (t rest))
       (string-equal name "foo")
       (set! total (+ total count))
       (set! x rest)))
This is just one of many other ways one could setup a matching
expression in elisp, the best is a balance between implementation
efficiency and readability.

And this divorces matching from destructuring. I suggest you try
rewriting one of the more complex pcase usages into this syntax and
see what people think of the result.

You want me to guess what you have in mind?  I have no idea.

I meant that you could try to take an example of a complex usage of pcase (one that seemed complex to you), some big expression or at least one that exhibits most of pcase's functionalities, and try rewriting it using an alternative syntax. And then judge for yourself, and then maybe poll others, which solution looks more readable and easier to understand.

I'll take the example pcase code from the Emacs manual:

(pcase (get-return-code x)
   ;; string
   ((and (pred stringp) msg)
         (message "%s" msg))
   ;; symbol
   ('success       (message "Done!"))
   ('would-block   (message "Sorry, can't do it now"))
   ('read-only     (message "The shmliblick is read-only"))
   ('access-denied (message "You do not have the needed rights"))
   ;; default
   (code           (message "Unknown return code %S" code)))

This is a simple use case, so its hard to use to draw any conclusions.

This is mostly value handling for a known type, which is to me a
different problem than destructuring, and be handled better by a
generalized value case structure.  But still:

(let ((msglist
         '((success       . "Done!")
           (would-block   . "Sorry, can't do it now")
           (read-only     . "The shmliblick is read-only")
           (access-denied . "You do not have the needed rights"))))
   (proto-case (get-return-code x)
     ((string msg) t (message "%s" msg))
     ((symbol sym) t (let ((pair (assq sym msglist)))
                       (if pair
                         (message (cdr pair))
                         (message "Unknown return symbol %S" sym))))
     ((t code)     t (message "Unknown return type %S" code))))

In this situation pcase situation is a slightly better, to my
sensibility's. [Now that pcase is written]

Indeed, I don't see an improvement either. I'd say it looks worse because of the slight increase in verbosity, but they're close enough.

That's why I suggested picking some relatively complex example to rewrite: more potential to show a difference.



reply via email to

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