emacs-diffs
[Top][All Lists]
Advanced

[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}
 



reply via email to

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