[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Emacs-diffs] fix/bug-31311-pcase-doc 279d548 14/18: transform ‘let’ ex
From: |
Thien-Thi Nguyen |
Subject: |
[Emacs-diffs] fix/bug-31311-pcase-doc 279d548 14/18: transform ‘let’ example |
Date: |
Tue, 15 May 2018 05:45:54 -0400 (EDT) |
branch: fix/bug-31311-pcase-doc
commit 279d548da1d2de53c9e569d08cd42a37985f4285
Author: Thien-Thi Nguyen <address@hidden>
Commit: Thien-Thi Nguyen <address@hidden>
transform ‘let’ example
- zonk "For example: ..." in table
- add elaborated (multi-para) example
- original used `QPAT (elegant, but a conceptual forw-ref)
- replacement is "reformulation" w/ micro-steps explanation
- better coverage (also uses ‘pred’, ‘app’, ‘or’)
- mention "default"
- bonus: w/ xrefs!
---
doc/lispref/control.texi | 109 +++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 106 insertions(+), 3 deletions(-)
diff --git a/doc/lispref/control.texi b/doc/lispref/control.texi
index 08fc8f1c..98e917f 100644
--- a/doc/lispref/control.texi
+++ b/doc/lispref/control.texi
@@ -407,9 +407,7 @@ Matches if @var{boolean-expression} evaluates to
address@hidden
Evaluates @var{expr} to get @var{exprval}
and matches if @var{exprval} matches @var{pattern}.
(It is called @code{let} because
address@hidden can bind symbols to values using @var{symbol}.
-For example:
address@hidden@code{((or `(key . ,val) (let val 5)) val)}}.)
address@hidden can bind symbols to values using @var{symbol}.)
@item (or @var{pattern1} @address@hidden)
Matches if one the argument U-patterns matches. As soon as the first
@@ -443,6 +441,111 @@ Lastly, @code{guard} matches if the boolean expression
evaluates to address@hidden
If all these sub-patterns match, @code{and} matches.
+Here is another example that shows how to reformulate a simple
+matching task from its traditional implementation
+(function @code{grok/traditional}) to one using
address@hidden (function @code{grok/pcase}).
+The docstring for both these functions is:
+``If OBJ is a string of the form "key:NUMBER", return NUMBER
+(a string). Otherwise, return the list ("149" default).''
+First, the traditional implementation (@pxref{Regular Expressions}):
+
address@hidden
address@hidden
+(defun grok/traditional (obj)
+ (if (and (stringp obj)
+ (string-match "^key:\\([[:digit:]]+\\)$" obj))
+ (match-string 1 obj)
+ (list "149" 'default)))
address@hidden group
+
address@hidden
+(grok/traditional "key:0") @result{} "0"
+(grok/traditional "key:149") @result{} "149"
+(grok/traditional 'monolith) @result{} ("149" default)
address@hidden group
address@hidden example
+
address@hidden
+The reformulation demonstrates @var{symbol} binding
+as well as some of the other pattern types.
+
address@hidden
+(defun grok/pcase (obj)
+ (pcase obj
address@hidden
+ ((or ; @r{line 1}
+ (and ; @r{line 2}
+ (pred stringp) ; @r{line 3}
+ (pred (string-match ; @r{line 4}
+ "^key:\\([[:digit:]]+\\)$")) ; @r{line 5}
+ (app (match-string 1) ; @r{line 6}
+ val)) ; @r{line 7}
+ (let val (list "149" 'default))) ; @r{line 8}
+ val))) ; @r{line 9}
address@hidden group
+
address@hidden
+(grok/pcase "key:0") @result{} "0"
+(grok/pcase "key:149") @result{} "149"
+(grok/pcase 'monolith) @result{} ("149" default)
address@hidden group
address@hidden example
+
address@hidden
+The bulk of @code{grok/pcase} is a single clause of a @code{pcase}
+form, the pattern on lines 1-8, the (single) body form on line 9.
+The pattern is @code{or}, which tries to match in turn its argument
+sub-patterns, first @code{and} (lines 2-7), then @code{let} (line 8),
+until one of them succeeds.
+
address@hidden TODO: add anchor (and maybe heading) above; add pxref here
+As in the previous example,
address@hidden begins with a @code{pred} sub-pattern to ensure
+the following sub-patterns work with an object of the correct
+type (string, in this case). If @address@hidden(stringp @var{expval})}}
+returns @code{nil}, @code{pred} fails, and thus @code{and} fails, too.
+
+The next @code{pred} (lines 4-5) evaluates
address@hidden@code{(string-match RX @var{expval})}}
+and matches if the result is address@hidden, which means
+that @var{expval} has the desired form: @code{key:NUMBER}.
+Again, failing this, @var{pred} fails and @code{and}, too.
+
+Lastly (in this series of @code{and} sub-patterns), @code{app}
+evaluates @address@hidden(match-string 1 @var{expval})}}
+to get a temporary value @var{tmp} (i.e., the ``NUMBER'' substring)
+and tries to match @var{tmp} against pattern @code{val}.
+Since that is a @var{symbol} pattern, it matches unconditionally
+and additionally binds @code{val} to @var{tmp}.
+
+Now that @code{app} has matched, all @code{and} sub-patterns
+have matched, and so @code{and} matches.
+Likewise, once @code{and} has matched, @code{or} matches
+and does not proceed to try sub-pattern @code{let} (line 9).
+
+Let's consider the situation where @code{obj} is not a string,
+or it is a string but has the wrong form.
+In this case, one of the @code{pred} (lines 3-5) fails to match,
+thus @code{and} (line 2) fails to match,
+thus @code{or} (line 1) proceeds to try sub-pattern @code{let} (line 9).
+
+First, @code{let} evaluates @address@hidden(list "149" 'default)}}
+to get @address@hidden("149" default)}}, the @var{exprval}, and then
+tries to match @var{exprval} against pattern @code{val}.
+Since that is a @var{symbol} pattern, it matches unconditionally
+and additionally binds @code{val} to @var{exprval}.
+Now that @code{let} has matched, @code{or} matches.
+
+Note how both @code{and} and @code{let} sub-patterns finish in the
+same way: by trying (always successfully) to match against the
address@hidden pattern @code{val}, in the process binding @code{val}.
+Thus, @code{or} always matches and control always passes
+to the body form (line 9).
+Because that is the last body form in a successfully matched
address@hidden clause, it is the value of @code{pcase} and likewise
+the return value of @code{grok/pcase} (@pxref{What Is a Function}).
+
@anchor{pcase-symbol-caveats}
@heading Caveats for @var{symbol} in @var{bigpat}
- [Emacs-diffs] fix/bug-31311-pcase-doc 0f1c170 06/18: settle on address@hidden pcase’ text, (continued)
- [Emacs-diffs] fix/bug-31311-pcase-doc 0f1c170 06/18: settle on address@hidden pcase’ text, Thien-Thi Nguyen, 2018/05/15
- [Emacs-diffs] fix/bug-31311-pcase-doc dc4b413 09/18: do ‘s/predfun/function/g’, Thien-Thi Nguyen, 2018/05/15
- [Emacs-diffs] fix/bug-31311-pcase-doc 5e2eeee 17/18: transform ‘get-return-code’ example, Thien-Thi Nguyen, 2018/05/15
- [Emacs-diffs] fix/bug-31311-pcase-doc e276ce7 13/18: transform ‘guard’ example, Thien-Thi Nguyen, 2018/05/15
- [Emacs-diffs] fix/bug-31311-pcase-doc ff41db6 12/18: (docstring) quote ‘pcase’ in QPAT docstring, Thien-Thi Nguyen, 2018/05/15
- [Emacs-diffs] fix/bug-31311-pcase-doc bd79b06 15/18: add anchor/heading to examples; fix typo, Thien-Thi Nguyen, 2018/05/15
- [Emacs-diffs] fix/bug-31311-pcase-doc d5dfe0e 02/18: expand on SYMBOL, Thien-Thi Nguyen, 2018/05/15
- [Emacs-diffs] fix/bug-31311-pcase-doc 0dffb69 10/18: (docstring) do s/predicate function/predicate/g, s/specified/formed/g, Thien-Thi Nguyen, 2018/05/15
- [Emacs-diffs] fix/bug-31311-pcase-doc 4ede733 16/18: refine example header, grouping, Thien-Thi Nguyen, 2018/05/15
- [Emacs-diffs] fix/bug-31311-pcase-doc 484c3ae 18/18: add xref to ‘(cl) Conditionals’, Thien-Thi Nguyen, 2018/05/15
- [Emacs-diffs] fix/bug-31311-pcase-doc 279d548 14/18: transform ‘let’ example,
Thien-Thi Nguyen <=