emacs-devel
[Top][All Lists]
Advanced

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

Re: The poor state of documentation of pcase like things.


From: Eli Zaretskii
Subject: Re: The poor state of documentation of pcase like things.
Date: Fri, 18 Dec 2015 10:55:21 +0200

> From: John Wiegley <address@hidden>
> Date: Thu, 17 Dec 2015 16:42:13 -0800
> Cc: Alan Mackenzie <address@hidden>, Emacs developers <address@hidden>
> 
> >>>>> Kaushal Modi <address@hidden> writes:
> 
> > I would welcome a short tutorial on how (and why) to use pcase.
> 
> The following is a brief pcase tutorial. I welcome any edits and comments.

Thanks, please find below a few questions of a naïve reader.

> Also, I wonder if anyone would be willing to hammer this into a form better
> suited to the Emacs Lisp manual.

I could try, but only if I understand this enough to write about it,
and if the description you posted is complete (is it?).  It's hard to
convert tutorials into a manual section otherwise.

> # QPatterns and UPatterns
> 
> To master `pcase', there are two types of patterns you must know: UPatterns
> and QPatterns. UPatterns are the "logical" aspect of pattern matching, where
> we describe the kind of data we'd like to match against, and other special
> actions to take when it matches; and QPatterns are the "literal" aspect,
> stating the exact form of a particular match.

What do "Q" and "U" stand for?  "Quoted" and "Unquoted", something
else?  When introducing terminology that is not English words, you
need to help the reader form a mental model by connecting terms to
words.

> The only special QPattern is the anti-quoting pattern, `,foo`

But the example doesn't use `,foo`, it uses just ,foo.  I guess `..`
here is some markdown-style "quoting", unrelated to the Lisp
backticks?

>     (pcase value
>       (`(1 2 ,(or `3 `4))
>        (message "Matched either the list (1 2 3) or (1 2 4)")))

Do 3 and 4 really have to be quoted here?  Why?

> When performing a match, if a symbol occurs within a UPattern, it binds
> whatever was found at that position to a local symbol of the same name.

"Local symbol" here meaning what? an un-interned symbol or a local
variable by that name?

>     (pcase value
>       (`(1 2 ,foo 3)
>        (message "Matched 1, 2, something now bound to foo, and 3"))
>       (foo
>        (message "Match anything at all, and bind it to foo!"))
>       (`(,the-car . ,the-cdr))
>        (message "Match any cons cell, binding the car and cdr locally"))

So to bind something to 'foo' you just use "foo", but to bind
something to 'the-car' and 'the-cdr' you need to use ",the-car" and
",the-cdr"?  Why the inconsistency?

> The reason for doing this is two-fold: Either to refer to a previous match
> later in the pattern (where it is compared using `eq'), or to make use of a
> matched value within the related code block:
> 
>     (pcase value
>       (`(1 2 ,foo ,foo 3)
>        (message "Matched (1 2 %s %s 3)" foo)))

??? Is "foo" here bound to 2 different values?  And how come the
format has 2 %s, but only one variable, foo, to provide values?

> We can express boolean logic within a pattern match using the `or` and `and`
> Patterns:
> 
>     (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 did you use 'lambda' for the 3rd predicate, but not for the 2nd?
Is it just a way to show off use of 'lambda', or is there some
significant difference between these 2 use cases that requires a
'lambda' in the latter case?  More generally, when is 'lambda'
required in a predicate like these ones?

>     (pcase value
>       (`(1 2 ,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"))))

How is using 'guard' here different from using a predicate?

> Note that in this example, the guard occurs at a match position, so even
> though the guard doesn't refer to what is being matched, if it passes, then
> whatever occurs at that position (the fourth element of the list), would be an
> unnamed successful matched.

What is the significance of an "unnamed successful matched"?

> This is rather bad form, so we can be more
> explicit about the logic here:
> 
>     (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"))))
> 
> 
> This means the same, but associates the guard with the value it tests, and
> makes it clear that we don't care what the fourth element is, only that it
> exists.

Again, how is this different from using a 'pred'?

> 
> ## Pattern let bindings
> 
> Within a pattern we can match sub-patterns, using a special form of let that
> has a meaning specific to `pcase':
> 
>     (pcase value
>       (`(1 2 ,(and foo (let 3 foo)))
>        (message "A weird way of matching (1 2 3)")))
> 
> This example is a bit contrived, but it allows us to build up complex guard
> patterns that might match against values captured elsewhere in the surrounding
> code:
> 
>     (pcase value1
>       (`(1 2 ,foo)
>        (pcase value2
>          (`(1 2 ,(and (let (or 3 4) foo) bar))
>           (message "A nested pcase depends on the results of the first")))))
> 
> Here the third value of `value2' -- which must be a list of exactly three
> elements, starting with 1 and 2 -- is being bound to the local variable `bar',
> but only if foo was a 3 or 4.

Why do you need the 'let' here?  Binding bar to the 3rd element can be
expressed without a 'let', I think.  And why is 'and' needed here?

> That's all there is to know about `pcase'! The other two utilities you might
> like to use are `pcase-let` and `pcase-let*`, which do similar things to their
> UPattern counter-part `let', but as regular Lisp forms:
> 
>     (pcase-let ((`(1 2 ,foo) value1)
>                 (`(3 4 ,bar) value2))
>       (message "value1 is a list of (1 2 %s); value2 ends with %s"
>                foo bar))

Isn't it true that pcase-let is just a short-hand for a pcase that
assigns values according to patterns, and has nil as the default
value?  If that's true, I think it explains better what pcase-let
does, especially when backed up by an example of a pcase and the
equivalent pcase-let.

Looking at the ELisp manual's node "Pattern matching case statement",
it sounds like everything you've described is already covered there,
so perhaps what we need is more examples?

Thanks.



reply via email to

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