guile-devel
[Top][All Lists]
Advanced

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

Re: [PATCH v3] docs/match: pattern matcher example makeover


From: Blake Shaw
Subject: Re: [PATCH v3] docs/match: pattern matcher example makeover
Date: Fri, 03 Feb 2023 21:14:40 +0700

Josselin Poiret <dev@jpoiret.xyz> writes:

> Hi Blake and David,
>
> We were talking about this very node of the documentation yesterday with
> Ludovic and zimoun, so here are my two cents. Rewriting this
> introduction is a very good idea, the current one is pretty hard to get
> into for novices.
>
> David Pirotte <david@altosw.be> writes:
>
>> Not at all - and quite annoying. imo.
>> So i'd 'vote' not to use them anywhere in the guile reference manual
>
> I agree that it's not "idiomatic Guile" so should probably be left out.

To avoid bikeshedding, I've reverted back to not use brackets.
>
> Regarding the examples, I think the first one is nice but the next one
> is too involved, using a named let which a lot of users might not know.
> I'd suggest demonstrating each feature without any extra prerequisite,
> to make it as accessible as possible.
>

I agree that it escalates quickly. I was hoping to juxtapose the obvious
with whats more involved in hopes of hitting a "sweet spot" where the
total novice can go through the examples one-by-one and still comprehend
them, while an experienced functional programmer without Scheme/Guile
experience can jump straight in, review a few examples, catch the drift
and keep working on what they are working on, without much reading.

I wanted to go straight from an arbitrary example to one with recursion
in order to show how to think "heads/tails" recursively with a
Scheme matcher, because I personally found it initially intimidating to
start doing recursive pattern matching in Scheme, and found few examples
that do so in a highly simplified form, making it confusing to translate
knowlege from other functional languages.

>From my POV, named let seems like a pretty standard feature of Scheme,
and its used throughout the docs (perhaps that isn't a good thing).

What if I followed it with an equivalent conditional version, and
used the more explicit "recur" or "lp" or "loop" as the let's name?

smth like:
...
≣
(let recur ((ns '(one two three four nine))
            (total 0)) 
  (if (equal? 1 (length ns))
      (+ total (english-base-ten->number (car ns)))
      (recur (cdr ns)
             (+ total (english-base-ten->number (car ns))))))

> The third example, introducing the ellipsis, uses 2 of them directly,
> with one nested! It also doesn't explain what the pattern variables are
> bound to when an ellipsis is involved.
just before the third example we have:
--
`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:` 
--
How would you improve on this?

Also it does explain what the pattern variables are bound to, but as the
result rather than in writing, which I think makes for more digestible
"reference" material.

> Also, the example data you're
> matching on looks too intimidating, which could scare novice readers.

I think this one may look complicated from afar, but I added it to [V2]
because it explicates something that can't be demonstrated from simpler
data and I think is often missed: that ellipsis allow pattern variables
to bind every for every instance of a pattern. I chose to show this
immediately, followed by simpler examples, so that the reader is exposed
this idea upfront.

take a simpler example:

(match '(a b (1 2 3 ))
  ((heads ... (tails ...))
   (format #t "heads: ~a ~%tails: ~a ~%" heads tails)))
⇒
heads: (a b) 
tails: (1 2 3) 

Psychologically, it is easy for the reader to not pickup on
the fact that ellipsis allow you to match over nested patterns.
This may cause readers to resort to using match with map when
its unneccessary.

The below contains two lists, (a.n b.n ((1.n 2.n 3.n) x.n y.n z.n)),
where the the letters and numbers follow an obvious order, and the
results show the effect of nesting patterns.

(match '((a.0 b.0 c.0 ((1.0 2.0 3.0) x.0 y.0 z.0)) 
         (a.1 b.1 c.1 ((1.1 2.1 3.1) x.1 y.1 z.1)))
  (((heads ... ((tails ...) . rest)) ...) 
   (begin 
    (format #t "heads: ~a ~%" heads)
    (format #t "tails: ~a ~%" tails)
    (format #t "rest:  ~a ~%" rest))))
⇒
heads: ((a.0 b.0 c.0) (a.1 b.1 c.1)) 
tails: ((1.0 2.0 3.0) (1.1 2.1 3.1)) 
rest:  ((x.0 y.0 z.0) (x.1 y.1 z.1)) 

I imagine the element names could be improved, and perhaps
the data structure simplified while preserving the lesson that
it contains, but I can't think of how that would be done, but
I'm open to suggestions. But overall, I think showing nested
patterns first off, followed by simpler examples that
ellucidate previous ones, is preferable so as to cater both
to the "reference" user as well as the total beginner.



reply via email to

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