unofficial mirror of guile-devel@gnu.org 
 help / color / mirror / Atom feed
* [PATCH v1 1/6] docs/match: add pattern matching examples
@ 2023-01-26 18:57 Blake Shaw
  2023-01-26 18:57 ` [PATCH v1 2/6] docs/match: rm unquote-splicing as it interferes with textinfo Blake Shaw
                   ` (6 more replies)
  0 siblings, 7 replies; 22+ messages in thread
From: Blake Shaw @ 2023-01-26 18:57 UTC (permalink / raw)
  To: guile-devel; +Cc: Blake Shaw

Hello all,

This commit introduces a set of (long overdue) examples to the
documentation on pattern matching discussed in the Guix Days
presentation which can be found here:
https://xana.lepiller.eu/guix-days-2022/guix-days-2022-documentation.mp4

As discussed in the Guix Days presentation, and agreed upon during the
corresponding brainstorming session, I'm introducing a set of examples
that intend to demonstrate the basics of the Shinn/Wright pattern
matcher, as well as touch on some of its subtleties.

Most paragraphs will be broken up into smaller peices with examples
interspersed throughout, according to the refactoring strategy of
"graduated expression" presented in my talk. The goal is to express the
pedagogical aim of examples naturally through graduality, reducing
"wordiness" primarily by with examples rather than reducing what has
already been written.

My apologies for taking so long to get to work on this! This summer
I was confronted with a unanticipated event that subsequently turned
my life upside down, causing my contributions to be low. I hope to be
increasing my contributions from here on, and fulfilling my obligations
concerning the documentation.

Best,
Blake

---
 doc/ref/match.texi | 138 ++++++++++++++++++++++++++++++++-------------
 1 file changed, 99 insertions(+), 39 deletions(-)

diff --git a/doc/ref/match.texi b/doc/ref/match.texi
index f5ea43118..105150886 100644
--- a/doc/ref/match.texi
+++ b/doc/ref/match.texi
@@ -24,52 +24,66 @@ written by Alex Shinn, and compatible with Andrew K. Wright's pattern
 matcher found in many Scheme implementations.
 
 @cindex pattern variable
-A pattern matcher can match an object against several patterns and
-extract the elements that make it up.  Patterns can represent any Scheme
-object: lists, strings, symbols, records, etc.  They can optionally contain
-@dfn{pattern variables}.  When a matching pattern is found, an
-expression associated with the pattern is evaluated, optionally with all
-pattern variables bound to the corresponding elements of the object:
+A pattern matcher does precisely what the name implies: it matches
+some arbitrary pattern, and returns some result accordingly.
 
 @example
-(let ((l '(hello (world))))
-  (match l           ;; <- the input object
-    (('hello (who))  ;; <- the pattern
-     who)))          ;; <- the expression evaluated upon matching
-@result{} world
+(define (english-base-ten->number name)
+  (match name
+    ('zero   0)
+    ('one    1)
+    ('two    2)
+    ('three  3)
+    ('four   4)
+    ('five   5)
+    ('six    6)
+    ('seven  7)
+    ('eight  8)
+    ('nine   9)))
+      
+(english-base-ten->number 'six)
+@result{} 6
+
+(apply + (map english-base-ten->number '(one two three four)))
+@result{} 10 
 @end example
 
-In this example, list @var{l} matches the pattern @code{('hello (who))},
-because it is a two-element list whose first element is the symbol
-@code{hello} and whose second element is a one-element list.  Here
-@var{who} is a pattern variable.  @code{match}, the pattern matcher,
-locally binds @var{who} to the value contained in this one-element
-list---i.e., the symbol @code{world}.  An error would be raised if
-@var{l} did not match the pattern.
-
-The same object can be matched against a simpler pattern:
+Pattern matchers may contain @dfn{pattern variables}, local bindings
+to all elements that match a pattern.
 
 @example
-(let ((l '(hello (world))))
-  (match l
-    ((x y)
-     (values x y))))
-@result{} hello
-@result{} (world)
+(let re ((ns '(one two three four ten))
+         (total 0)) 
+  (match ns
+    ((e) (+ total (english-base-ten->number e)))
+    ((e . es) 
+     (re es (+ total (english-base-ten->number e))))))
+@result{} 20
 @end example
 
-Here pattern @code{(x y)} matches any two-element list, regardless of
-the types of these elements.  Pattern variables @var{x} and @var{y} are
-bound to, respectively, the first and second element of @var{l}.
-
-Patterns can be composed, and nested.  For instance, @code{...}
+In this example, the list @var{ns} matches the pattern
+@code{(e . es)}, where the pattern variable @var{e} corresponds 
+to the `car` of @var{ns} and the pattern variable @var{es}
+corresponds to the `cdr` of @var{ns}.
+
+A tail call @code{re} is then initiated and we `cdr` down the
+list by recurring on the tail @var{es}, applying our matcher
+@code{english-base-ten->number} to each element of @var{ns} until
+only a single element @code{(e)} remains, causing the @var{total}
+to be computed.  In modern Scheme programming it is common to use
+@code{match} in place of the more verbose but familiar combination
+of @code{cond}, @code{car} and @code{cdr}, so it's important to
+understand how these idioms translate. 
+
+Patterns can be composed and nested.  For instance, @code{...}
 (ellipsis) means that the previous pattern may be matched zero or more
 times in a list:
 
 @example
-(match lst
-  (((heads tails ...) ...)
-   heads))
+(match '(((a b c) e f g) 1 2 3)  
+  (((head ...) tails ...)
+   `(,@tails ,head)))
+@result{} (1 2 3 ((a b c) e f g))
 @end example
 
 @noindent
@@ -79,6 +93,52 @@ lst)}.  However, it performs additional checks to make sure that
 @var{lst} and the lists therein are proper lists, as prescribed by the
 pattern, raising an error if they are not.
 
+A pattern matcher can match an object against several patterns and
+extract the elements that make it up. 
+
+@example
+(let ((m '((a . b) (c . d) (e . f))))
+  (match m
+    (((left . right) ...) left)))
+@result{} (a c e)
+@end example
+
+@example
+(let ((m '((1 . (a . b)) (2 . (c . d)) (3 . (e . f)))))
+  (match m
+    (((key . (left . right)) ...) 
+     (fold-right acons '() key right ))))
+@result{} ((1 . b) (2 . d) (3 . f))
+@end example
+
+Patterns can represent any Scheme object: lists, strings, symbols,
+records, etc.
+
+@example
+(let re ((m #(a "b" c "d" e "f" g)))
+   (match m
+     ((or (e) #(e)) e)
+     ((or #(e1 e2 es ...)
+	   (e1 e2 es ...)) 
+       (cons (cons e1 e2)
+ 	     (re es)))))
+@result{} ((a . "b") (c . "d") (e . "f") . g) 
+@end example
+
+When a matching pattern is found, an expression associated with the
+pattern is evaluated, optionally with all pattern variables bound to
+the corresponding elements of the object.
+
+@example
+(let re ((m '(a b c d e f g h i)))
+   (match m
+     ((e) e)
+     ((e1 e2 es ...) 
+      (acons e1 e2
+ 	     (re es)))))
+@result{} ((a . b) (c . d) (e . f) (g . h) . i)
+@end example
+
 Compared to hand-written code, pattern matching noticeably improves
 clarity and conciseness---no need to resort to series of @code{car} and
 @code{cdr} calls when matching lists, for instance.  It also improves
@@ -229,11 +289,11 @@ expressions.
 @end deffn
 
 @example
-((match-lambda
-   (('hello (who))
-    who))
- '(hello (world)))
-@result{} world
+(define flatten-singletons 
+   (match-lambda (((s) ...) s)))
+
+(flatten-singletons '((x) (y) (z)))
+@result{} (x y z) 
 @end example
 
 @deffn {Scheme Syntax} match-lambda* clause1 clause2 @dots{}
-- 
2.39.1




^ permalink raw reply related	[flat|nested] 22+ messages in thread

end of thread, other threads:[~2023-01-31  3:59 UTC | newest]

Thread overview: 22+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-01-26 18:57 [PATCH v1 1/6] docs/match: add pattern matching examples Blake Shaw
2023-01-26 18:57 ` [PATCH v1 2/6] docs/match: rm unquote-splicing as it interferes with textinfo Blake Shaw
2023-01-27 16:27   ` Maxime Devos
2023-01-28  9:14     ` Blake Shaw
2023-01-28 13:08       ` Maxime Devos
2023-01-29  3:09         ` Blake Shaw
2023-01-26 18:57 ` [PATCH v1 3/6] docs/match: add reverse nested list example Blake Shaw
2023-01-26 18:57 ` [PATCH v1 4/6] docs/match: match-let* unwrap example Blake Shaw
2023-01-26 18:58 ` [PATCH v1 5/6] docs/fixup: @cindex was in the wrong place Blake Shaw
2023-01-26 18:58 ` [PATCH v1 6/6] docs/match:style reviewing with pdf, adding newlines Blake Shaw
2023-01-28 13:18 ` [PATCH v1 1/6] docs/match: add pattern matching examples Maxime Devos
2023-01-28 19:10   ` randomlooser
2023-01-28 19:23     ` randomlooser
     [not found]   ` <CAKjmbcA9TeuC0HWE53cG4EfautTcW5s9tyh0tCXUvicAQiBFKQ@mail.gmail.com>
2023-01-29 14:23     ` Maxime Devos
2023-01-28 13:48 ` Maxime Devos
     [not found]   ` <CAKjmbcAucYA9j7suY1gEAO512pn+90ED33Wq5Z7CjrBsqxgrbw@mail.gmail.com>
2023-01-29 15:30     ` Maxime Devos
2023-01-30  0:49       ` Blake Shaw
2023-01-30 19:56         ` Aleix Conchillo Flaqué
2023-01-30 19:57           ` Aleix Conchillo Flaqué
2023-01-31  2:53           ` Maxime Devos
2023-01-31  3:59             ` Aleix Conchillo Flaqué
2023-01-31  2:28         ` [PATCH v1 1/6] docs/match: add pattern matching examples + CoC Maxime Devos

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).