emacs-devel
[Top][All Lists]
Advanced

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

Re: Replace trivial pcase occurrences in the Emacs sources


From: Joost Kremers
Subject: Re: Replace trivial pcase occurrences in the Emacs sources
Date: Wed, 24 Oct 2018 10:34:23 +0200
User-agent: Mutt/1.9.4 (2018-02-28)

On Wed, Oct 24, 2018 at 12:51:35AM -0400, Richard Stallman wrote:
> [[[ To any NSA and FBI agents reading my email: please consider    ]]]
> [[[ whether defending the US Constitution against all enemies,     ]]]
> [[[ foreign or domestic, requires you to follow Snowden's example. ]]]
> 
>   > In what sense is the above cl-case more clear than the pcase equivalent?
>   > I'm not saying the pcase version is better in those cases, but I think
>   > the respective advantages and disadvantages pretty much balance out.
> 
> I also wonder.  Is it simply that people find pcase unfamiliar?

Well, I can't speak for others, but personally, though I find pattern matching 
as a concept straightforward and intuitive, pcase syntax seems unnecessarily 
complex and unintuitive.

For example, John Wiegley's tutorial on pcase at 
<http://newartisans.com/2016/01/pattern-matching-with-pcase/> has the following 
example:

```
(pcase value
  (`(,_ 1 2)
   (message "Matched a list of anything followed by (1 2)")))
```

It is not clear to me why I couldn't simply write:

```
(pcase value
  ((_ 1 2)
   (message "Matched a list of anything followed by (1 2)")))
```

I *can* understand the need to write:

```
(pcase value
  (`(1 2 ,foo 3)
   (message "Matched 1, 2, something now bound to foo, and 3")))
```

Instead of:

```
(pcase value
  ((1 2 foo 3)
   (message "Matched 1, 2, something now bound to foo, and 3")))
```

This is obviously done in order to be able to match against the symbol `foo' 
while at the same time be able to match anything and bind it to the symbol 
`foo'. And even though this syntax with backquote and comma looks familiar to 
anyone who's ever written a macro, their meaning is subtly different from their 
meaning in macros. In pcase, «,foo» does *not* mean «evaluate `foo'», it means 
something like «use `foo' as a variable».

So, while I understand the reasoning, it still makes me wonder why I can't 
write something like this:

```
(pcase value
  ((1 2 % 3)
   (message "Matched 1, 2, something now bound to %, and 3")))
```

That is, use a special symbol (I borrowed % from Clojure's anonymous functions) 
to indicate that I want to match against any value and at the same time bind 
that value. Obviously, the following:

```
(pcase value
  ((1 2 % %)
   (message "Matched 1, 2, something now bound to %, and that same something 
again")))
```

would then match lists of the form (1 2 3 3), not (1 2 3 4). If you need to 
bind multiple values, I could imagine using something like:

```
(pcase value
  ((1 2 %1 %2)
   (message "Matched 1, 2, something now bound to %1, and something (else) 
bound to %2")))
```

Also, the use of `pred' and `guard' seem unnecessary. Instead of:

```
(pcase value
  (`(1 2 ,(or 3 4)
     ,(and (pred stringp)
           (pred (string> "aaa"))
           (pred (lambda (x) (> (length x) 10)))))
   (message "Matched 1, 2, 3 or 4, and a long string "
            "that is lexically greater than 'aaa'")))
```

why not write:

```
(pcase value
  ((1 2 (or 3 4)
    (and (stringp %)
         (string> "aaa" %)
         (> (length %) 10)))
   (message "Matched 1, 2, 3 or 4, and a long string "
            "that is lexically greater than 'aaa'")))
```

Similarly, the example:

```
(pcase value
  (`(1 2 ,(and foo (guard (and (not (numberp foo)) (/= foo 10)))) _)
   (message "Matched 1, 2, anything, and then anything again, "
            "but only if the first anything wasn't the number 10"))))
```

uses `(and foo (guard ...))' to bind a value to `foo' and apply a predicate to 
it. That's a coding pattern that you need to be familiar with in order to 
understand what it does. (John explains it in his tutorial, but if I had met 
this in the wild, I'd probably be puzzled by it at first). The % syntax would 
seem to make this simpler as well:

```
(pcase value
  ((1 2 (and (not (numberp %)) (/= % 10)) _)
   (message "Matched 1, 2, anything, and then anything again, "
            "but only if the first anything wasn't the number 10"))))
```

This example also shows that `and' has a meaning in pcase that is subtly 
different from its usual meaning in Lisp: `and' in a pcase 'UPattern' (as the 
manual calls it) is not a logical `and' in the sense that it tests its 
arguments for truthiness. Rather, it means «both arguments of `and' must apply 
to the value at this position *regardless of truthiness*». (The `and' inside 
the guard does have the usual meaning, of course.)

Mind you, I'm not arguing that pcase should be changed or replaced with 
something that has this more intuitive (to me, anyway) syntax. I'm just trying 
to explain why I personally find pcase difficult to wrap my head around, and 
why I think this difficulty has to do with its syntax, which is different in 
subtle ways, to such an extent that you can't, as an Elisp programmer tackling 
pcase for the first time, just build on what you already know. You need to 
actually bend your mind to incorporate the new stuff. Moreover, at first sight, 
there doesn't seem to be much of an advantage to this syntax, since an 
alternative syntax that doesn't have the same disadvantage seems feasible.

I say "seems", because it's entirely possible that this particular syntax has 
capabilities that wouldn't be possible with a simpler syntax. But for a pcase 
newbie, that's not immediately obvious. The only reason that I can think of why 
the %-syntax or something similar isn't used is that it's dangerous in an 
environment that doesn't have lexical scope...

Just my two cents, of course.


-- 
Joost Kremers
Life has its moments



reply via email to

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