* [PATCH] doc: Extend documentation for (ice-9 match)
@ 2023-09-06 14:06 Tomas Volf
2023-09-19 22:57 ` Maxime Devos
0 siblings, 1 reply; 4+ messages in thread
From: Tomas Volf @ 2023-09-06 14:06 UTC (permalink / raw)
To: guile-devel; +Cc: Tomas Volf
Extend the documentation for (ice-9 match) module with explanation of
some of the patterns and also provide more examples for them. That
should make it more useful for people trying to use the module for the
first time just based on the documentation.
* doc/ref/match.texi (Pattern Matching): Explain some patterns and
provide more examples
---
When I tried to use (ice-9 match) for the first time, I was not able to,
except the most basic usage. The documentation was not very helful, so
I went to the IRC. I got help, but I was also asked to try to
contribute to the docs with examples that would have helped me in the
first place.
I think even more additions would be useful, but I still do not
understand the pattern matching fully, so they are not a part of this
patch. Examples would be: How and when I should use quasi-patterns?
What does `ooo' stand for? Does `box' refer to SRFI-111 or something
else?
I was following the HACKING file, so I added myself into the THANKS
file, I am not sure if I was supposed to for this relatively trivial
change.
THANKS | 1 +
doc/ref/match.texi | 75 ++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 76 insertions(+)
diff --git a/THANKS b/THANKS
index aa4877e95..bb07cda83 100644
--- a/THANKS
+++ b/THANKS
@@ -38,6 +38,7 @@ Contributors since the last release:
BT Templeton
David Thompson
Bake Timmons
+ Tomas Volf
Mark H Weaver
Göran Weinholt
Ralf Wildenhues
diff --git a/doc/ref/match.texi b/doc/ref/match.texi
index f5ea43118..b5a0147fa 100644
--- a/doc/ref/match.texi
+++ b/doc/ref/match.texi
@@ -181,6 +181,81 @@ The names @code{quote}, @code{quasiquote}, @code{unquote},
@code{or}, @code{not}, @code{set!}, @code{get!}, @code{...}, and
@code{___} cannot be used as pattern variables.
+@code{string}, @code{number}, and others refer to literal strings,
+numbers, and others. Therefore pattern @code{string} binds the value to
+identifier @code{string}, pattern @code{"string"} matches if the value
+is @code{"string"}. Example demonstrating this (by using very bad
+naming):
+
+@example
+(let ()
+ (match "foo"
+ (number number)))
+@result{} "foo"
+@end example
+
+The field operator (@code{(= field pat)}) has no relation to the fields
+of SRFI-9 records. The @code{field} should be an expression evaluating
+to a procedure taking a single argument, and @code{pat} is matched
+against the return value. Simple example:
+
+@example
+(let ()
+ (match '(1 2)
+ ((= cadr x)
+ x)))
+@result{} 2
+@end example
+
+The record operator(@code{($ record-name pat_1 ... pat_n)}) can be used
+for matching SRFI-9 and SRFI-99 records. Patterns are matched against
+the slots in order, not all have to be present, and there is no way to
+skip a slot. Example demonstrating the usage:
+
+@example
+(define-record-type <foo>
+ (make-foo bar baz zab)
+ foo?
+ (bar foo-bar)
+ (baz foo-baz)
+ (zab foo-zab))
+
+(let ((obj (make-foo 1 '2 "three")))
+ (match obj
+ ;; Make sure obj is a <foo> instance, with bar slot being a number
+ ;; and zab slot being a string. We do not care about baz slot,
+ ;; therefore we use _ to match anything.
+ (($ <foo> (? number?) _ (? string?))
+ "ok")))
+@result{} "ok"
+@end example
+
+If you need to ensure that a value is of a specific record type and at
+the same time bind it to a variable, the record operator will not be
+enough by itself, since you can only capture the fields. You would need
+to combine it with other patterns, for example @code{(? foo? obj)}.
+
+When you need to apply multiple patterns, or a check and a pattern, you
+can use (@code{(? predicate pat_1 ... pat_n)}) for that. The patterns
+are evaluated is if in the @code{(and ...)}. If, for example, you want
+to check something is a symbol and at the same time bind the value to a
+variable, it could look like this:
+
+@example
+(let ()
+ (match '(delete . some-id)
+ (('delete . (? symbol? id))
+ ;; We now could, for example, use the id to delete from some alist.
+ id)))
+@result{} some-id
+@end example
+
+@c FIXME: Remove this remark once everything is clearly described and
+@c consulting the comment is no longer necessary.
+If you are unclear about how something works, you can try consulting the
+large comment at the top of the @code{module/ice-9/match.upstream.scm}
+file in your guile distribution.
+
Here is a more complex example:
@example
--
2.41.0
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH] doc: Extend documentation for (ice-9 match)
2023-09-06 14:06 [PATCH] doc: Extend documentation for (ice-9 match) Tomas Volf
@ 2023-09-19 22:57 ` Maxime Devos
2023-10-15 17:40 ` Tomas Volf
0 siblings, 1 reply; 4+ messages in thread
From: Maxime Devos @ 2023-09-19 22:57 UTC (permalink / raw)
To: Tomas Volf, guile-devel
[-- Attachment #1.1.1: Type: text/plain, Size: 7769 bytes --]
Op 06-09-2023 om 16:06 schreef Tomas Volf:
> Extend the documentation for (ice-9 match) module with explanation of
> some of the patterns and also provide more examples for them. That
> should make it more useful for people trying to use the module for the
> first time just based on the documentation.
>
> * doc/ref/match.texi (Pattern Matching): Explain some patterns and
> provide more examples
> ---
> When I tried to use (ice-9 match) for the first time, I was not able to,
> except the most basic usage. The documentation was not very helful, so
> I went to the IRC. I got help, but I was also asked to try to
> contribute to the docs with examples that would have helped me in the
> first place.
>
> I think even more additions would be useful, but I still do not
> understand the pattern matching fully, so they are not a part of this
> patch. Examples would be: How and when I should use quasi-patterns?
> What does `ooo' stand for? Does `box' refer to SRFI-111 or something
> else?
Note: there is a previous patch for improving (ice-9 match)
documentation named ‘[PATCH v3] docs/match: pattern matcher example
makeover’, though IIRC it needed some changes. Maybe you can adapt some
things from it. As long as it doesn't descend in fake gatekeeping
accusations again, it would be nice if it wasn't for nothing.
Smaller incremental improvements like this would also be nice, though.
>
> I was following the HACKING file, so I added myself into the THANKS
> file, I am not sure if I was supposed to for this relatively trivial
> change.
I think you aren't supposed to (whether it is trivial or not). Instead,
I think that others are supposed to add you to THANKS, otherwise you
would be thanking yourself. That is, however, a personal disagreement I
have with HACKING.
I think that triviality or not is irrelevant; time spent on evaluating
whether something is trivial or not is better spent on doing more
contributors. Besides, THANKS says ‘Contributors since the last
release’, not ‘Contributors of non-trivial changes since the last release’.
>
> THANKS | 1 +
> doc/ref/match.texi | 75 ++++++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 76 insertions(+)
>
> diff --git a/THANKS b/THANKS
> index aa4877e95..bb07cda83 100644
> --- a/THANKS
> +++ b/THANKS
> @@ -38,6 +38,7 @@ Contributors since the last release:
> BT Templeton
> David Thompson
> Bake Timmons
> + Tomas Volf
> Mark H Weaver
> Göran Weinholt
> Ralf Wildenhues
> diff --git a/doc/ref/match.texi b/doc/ref/match.texi
> index f5ea43118..b5a0147fa 100644
> --- a/doc/ref/match.texi
> +++ b/doc/ref/match.texi
> @@ -181,6 +181,81 @@ The names @code{quote}, @code{quasiquote},
@code{unquote},
> @code{or}, @code{not}, @code{set!}, @code{get!}, @code{...}, and
> @code{___} cannot be used as pattern variables.
>
> +@code{string}, @code{number}, and others refer to literal strings,
> +numbers, and others. Therefore pattern @code{string} binds the value to
> +identifier @code{string}, pattern @code{"string"} matches if the value
> +is @code{"string"}.
It would do pause after ‘therefore’, not ‘before’. Might just be a
personal thing, though. Also, something about joining two sentences
with a comma instead of ‘and’ bothers me. Also², I find it difficult to
tell whether adding ‘the’ before ‘pattern’ would be better or worse.
What do you think?
‘Therefore, pattern @code{string} binds the value to
> Therefore the pattern @code{string} binds the value to
> the identifier @code{string} and the pattern [...].
> Example demonstrating this (by using very bad
> +naming):
Maybe ‘An example’? But again, dunno.
> +
> +@example
> +(let ()
> + (match "foo"
> + (number number)))
> +@result{} "foo"
> +@end example
> +
> +The field operator (@code{(= field pat)}) has no relation to the fields
> +of SRFI-9 records. The @code{field} should be an expression evaluating
> +to a procedure taking a single argument, and @code{pat} is matched
> +against the return value. Simple example:
s/SRFI-9 records/records
There's other methods for defining records to that it has no relation too!
> +@example
> +(let ()
> + (match '(1 2)
> + ((= cadr x)
> + x)))
> +@result{} 2
> +@end example
> +
> +The record operator(@code{($ record-name pat_1 ... pat_n)}) can be used
> +for matching SRFI-9 and SRFI-99 records. Patterns are matched against
> +the slots in order, not all have to be present, and there is no way to
> +skip a slot. Example demonstrating the usage:
Probably also RNRS records, structs and (ice-9 records), though I
haven't tested that.
Basically, all record types except perhaps GOOPS.
Though perhaps no slot order is guaranteed for RNRS and GOOPS, even if
it happens to work currently? Dunno.
I don't think it's _supposed_ to work with opaque RNRS records, but
that's probably not yet implemented.
> +@example
> +(define-record-type <foo>
> + (make-foo bar baz zab)
> + foo?
> + (bar foo-bar)
> + (baz foo-baz)
> + (zab foo-zab))
> +
> +(let ((obj (make-foo 1 '2 "three")))
> + (match obj
> + ;; Make sure obj is a <foo> instance, with bar slot being a number
> + ;; and zab slot being a string. We do not care about baz slot,
> + ;; therefore we use _ to match anything.
> + (($ <foo> (? number?) _ (? string?))
> + "ok")))
> +@result{} "ok"
> +@end example
You could inline 'obj' here -- unless there is a bug, match doesn't
evaluate its ‘argument’ multiple times.
> +
> +If you need to ensure that a value is of a specific record type and at
> +the same time bind it to a variable, the record operator will not be
> +enough by itself, since you can only capture the fields. You would need
> +to combine it with other patterns, for example @code{(? foo? obj)}.
> +
> +When you need to apply multiple patterns, or a check and a pattern, you
> +can use (@code{(? predicate pat_1 ... pat_n)}) for that. The patterns
> +are evaluated is if in the @code{(and ...)}.
That last sentence needs a grammar check.
> If, for example, you want
> +to check something is a symbol and at the same time bind the value to a
> +variable, it could look like this:
s/something/if something
or
s/something/whether something
> +
> +@example
> +(let ()
> + (match '(delete . some-id)
> + (('delete . (? symbol? id))
> + ;; We now could, for example, use the id to delete from some alist.
> + id)))
Slightly misleading: while in this particular example you don't need it,
you can also use ‘and’ for that. Especially useful if there is no
predicate in play/if the predicate would be (const #true).
Whereas the previous 'let' might just be a matter of personal style,
this let serves no purpose at all. I would eliminate this distraction
to eliminate the tiny risk that someone might be confused by it.
> +@result{} some-id
> +@end example
> +
> +@c FIXME: Remove this remark once everything is clearly described and
> +@c consulting the comment is no longer necessary.
> +If you are unclear about how something works, you can try consulting the
> +large comment at the top of the @code{module/ice-9/match.upstream.scm}
> +file in your guile distribution.
s/guile/Guile.
That's not supposed to be there, but given the current (lack of) (ice-9
match) documentation, I suppose it's reasonable.
Best regards,
Maxime.
[-- Attachment #1.1.2: OpenPGP public key --]
[-- Type: application/pgp-keys, Size: 929 bytes --]
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 236 bytes --]
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH] doc: Extend documentation for (ice-9 match)
2023-09-19 22:57 ` Maxime Devos
@ 2023-10-15 17:40 ` Tomas Volf
2023-10-17 20:41 ` Maxime Devos
0 siblings, 1 reply; 4+ messages in thread
From: Tomas Volf @ 2023-10-15 17:40 UTC (permalink / raw)
To: Maxime Devos; +Cc: guile-devel
[-- Attachment #1: Type: text/plain, Size: 9715 bytes --]
Hello,
thanks for the review! My reactions are below.
On 2023-09-20 00:57:33 +0200, Maxime Devos wrote:
>
>
> Op 06-09-2023 om 16:06 schreef Tomas Volf:
> > Extend the documentation for (ice-9 match) module with explanation of
> > some of the patterns and also provide more examples for them. That
> > should make it more useful for people trying to use the module for the
> > first time just based on the documentation.
> >
> > * doc/ref/match.texi (Pattern Matching): Explain some patterns and
> > provide more examples
> > ---
> > When I tried to use (ice-9 match) for the first time, I was not able to,
> > except the most basic usage. The documentation was not very helful, so
> > I went to the IRC. I got help, but I was also asked to try to
> > contribute to the docs with examples that would have helped me in the
> > first place.
> >
> > I think even more additions would be useful, but I still do not
> > understand the pattern matching fully, so they are not a part of this
> > patch. Examples would be: How and when I should use quasi-patterns?
> > What does `ooo' stand for? Does `box' refer to SRFI-111 or something
> > else?
> Note: there is a previous patch for improving (ice-9 match) documentation
> named ‘[PATCH v3] docs/match: pattern matcher example makeover’, though IIRC
> it needed some changes. Maybe you can adapt some things from it. As long
> as it doesn't descend in fake gatekeeping accusations again, it would be
> nice if it wasn't for nothing.
I managed to find it, and there even seems to be a v4. I sadly do not have the
time to work through it right now, and I do not want to make any promises
regarding if/when I will have it. So for now I incorporated your feedback and
will sent it as v v2.
>
> Smaller incremental improvements like this would also be nice, though.
>
> >
> > I was following the HACKING file, so I added myself into the THANKS
> > file, I am not sure if I was supposed to for this relatively trivial
> > change.
> I think you aren't supposed to (whether it is trivial or not). Instead, I
> think that others are supposed to add you to THANKS, otherwise you would be
> thanking yourself. That is, however, a personal disagreement I have with
> HACKING.
>
> I think that triviality or not is irrelevant; time spent on evaluating
> whether something is trivial or not is better spent on doing more
> contributors. Besides, THANKS says ‘Contributors since the last release’,
> not ‘Contributors of non-trivial changes since the last release’.
Makes sense, removed.
>
> >
> > THANKS | 1 +
> > doc/ref/match.texi | 75 ++++++++++++++++++++++++++++++++++++++++++++++
> > 2 files changed, 76 insertions(+)
> >
> > diff --git a/THANKS b/THANKS
> > index aa4877e95..bb07cda83 100644
> > --- a/THANKS
> > +++ b/THANKS
> > @@ -38,6 +38,7 @@ Contributors since the last release:
> > BT Templeton
> > David Thompson
> > Bake Timmons
> > + Tomas Volf
> > Mark H Weaver
> > Göran Weinholt
> > Ralf Wildenhues
> > diff --git a/doc/ref/match.texi b/doc/ref/match.texi
> > index f5ea43118..b5a0147fa 100644
> > --- a/doc/ref/match.texi
> > +++ b/doc/ref/match.texi
> > @@ -181,6 +181,81 @@ The names @code{quote}, @code{quasiquote},
> @code{unquote},
> > @code{or}, @code{not}, @code{set!}, @code{get!}, @code{...}, and
> > @code{___} cannot be used as pattern variables.
> >
> > +@code{string}, @code{number}, and others refer to literal strings,
> > +numbers, and others. Therefore pattern @code{string} binds the value to
> > +identifier @code{string}, pattern @code{"string"} matches if the value
> > +is @code{"string"}.
> It would do pause after ‘therefore’, not ‘before’. Might just be a personal
> thing, though. Also, something about joining two sentences with a comma
> instead of ‘and’ bothers me. Also², I find it difficult to tell whether
> adding ‘the’ before ‘pattern’ would be better or worse. What do you think?
Maybe. I am not that skilled with articles, so I defer to you here. It at
least does not sound worse to me.
>
> ‘Therefore, pattern @code{string} binds the value to
>
> > Therefore the pattern @code{string} binds the value to
> > the identifier @code{string} and the pattern [...].
>
> > Example demonstrating this (by using very bad
> > +naming):
> Maybe ‘An example’? But again, dunno.
Here as well.
>
> > +
> > +@example
> > +(let ()
> > + (match "foo"
> > + (number number)))
> > +@result{} "foo"
> > +@end example
> > +
> > +The field operator (@code{(= field pat)}) has no relation to the fields
> > +of SRFI-9 records. The @code{field} should be an expression evaluating
> > +to a procedure taking a single argument, and @code{pat} is matched
> > +against the return value. Simple example:
>
> s/SRFI-9 records/records
>
> There's other methods for defining records to that it has no relation too!
Ah, good point.
>
> > +@example
> > +(let ()
> > + (match '(1 2)
> > + ((= cadr x)
> > + x)))
> > +@result{} 2
> > +@end example
> > +
> > +The record operator(@code{($ record-name pat_1 ... pat_n)}) can be used
> > +for matching SRFI-9 and SRFI-99 records. Patterns are matched against
> > +the slots in order, not all have to be present, and there is no way to
> > +skip a slot. Example demonstrating the usage:
> Probably also RNRS records, structs and (ice-9 records), though I haven't
> tested that.
>
> Basically, all record types except perhaps GOOPS.
>
> Though perhaps no slot order is guaranteed for RNRS and GOOPS, even if it
> happens to work currently? Dunno.
>
> I don't think it's _supposed_ to work with opaque RNRS records, but that's
> probably not yet implemented.
I decided to just leave out the type and went with "for matching records."
There seems to be many kinds, and I have no idea with which it does work. Being
less precise (no type) is probably better than being wrong.
>
> > +@example
> > +(define-record-type <foo>
> > + (make-foo bar baz zab)
> > + foo?
> > + (bar foo-bar)
> > + (baz foo-baz)
> > + (zab foo-zab))
> > +
> > +(let ((obj (make-foo 1 '2 "three")))
> > + (match obj
> > + ;; Make sure obj is a <foo> instance, with bar slot being a number
> > + ;; and zab slot being a string. We do not care about baz slot,
> > + ;; therefore we use _ to match anything.
> > + (($ <foo> (? number?) _ (? string?))
> > + "ok")))
> > +@result{} "ok"
> > +@end example
> You could inline 'obj' here -- unless there is a bug, match doesn't evaluate
> its ‘argument’ multiple times.
I am not aware of any bugs here, but I wanted to adhere to the style of the
original examples:
(let ((l '(hello (world))))
(match l ;; <- the input object
(('hello (who)) ;; <- the pattern
who))) ;; <- the expression evaluated upon matching
I can inline it if you would prefer.
>
> > +
> > +If you need to ensure that a value is of a specific record type and at
> > +the same time bind it to a variable, the record operator will not be
> > +enough by itself, since you can only capture the fields. You would need
> > +to combine it with other patterns, for example @code{(? foo? obj)}.
> > +
> > +When you need to apply multiple patterns, or a check and a pattern, you
> > +can use (@code{(? predicate pat_1 ... pat_n)}) for that. The patterns
> > +are evaluated is if in the @code{(and ...)}.
> That last sentence needs a grammar check.
Right, typo corrected.
>
> > If, for example, you want
> > +to check something is a symbol and at the same time bind the value to a
> > +variable, it could look like this:
> s/something/if something
>
> or
>
> s/something/whether something
>
> > +
> > +@example
> > +(let ()
> > + (match '(delete . some-id)
> > + (('delete . (? symbol? id))
> > + ;; We now could, for example, use the id to delete from some alist.
> > + id)))
> Slightly misleading: while in this particular example you don't need it, you
> can also use ‘and’ for that. Especially useful if there is no predicate in
> play/if the predicate would be (const #true).
I think I understand what you mean, but I was not sure how to reword it to make
it less misleading. So I instead added one more paragraph exonerating the (and
...).
>
> Whereas the previous 'let' might just be a matter of personal style, this
> let serves no purpose at all. I would eliminate this distraction to
> eliminate the tiny risk that someone might be confused by it.
The "a more complex example" uses the (let () ...) form, so I just did the same.
Now I realize it is used to scope the (define-record-type). I removed the let
from here and from few other places where it was not required.
>
> > +@result{} some-id
> > +@end example
> > +
> > +@c FIXME: Remove this remark once everything is clearly described and
> > +@c consulting the comment is no longer necessary.
> > +If you are unclear about how something works, you can try consulting the
> > +large comment at the top of the @code{module/ice-9/match.upstream.scm}
> > +file in your guile distribution.
> s/guile/Guile.
>
> That's not supposed to be there, but given the current (lack of) (ice-9
> match) documentation, I suppose it's reasonable.
>
> Best regards,
> Maxime.
Have a nice day,
Tomas
--
There are only two hard things in Computer Science:
cache invalidation, naming things and off-by-one errors.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH] doc: Extend documentation for (ice-9 match)
2023-10-15 17:40 ` Tomas Volf
@ 2023-10-17 20:41 ` Maxime Devos
0 siblings, 0 replies; 4+ messages in thread
From: Maxime Devos @ 2023-10-17 20:41 UTC (permalink / raw)
To: Tomas Volf; +Cc: guile-devel
[-- Attachment #1.1.1: Type: text/plain, Size: 768 bytes --]
Op 15-10-2023 om 19:40 schreef Tomas Volf:
> I am not aware of any bugs here, but I wanted to adhere to the style of the
> original examples:
>
> (let ((l '(hello (world))))
> (match l ;; <- the input object
> (('hello (who)) ;; <- the pattern
> who))) ;; <- the expression evaluated upon matching
>
> I can inline it if you would prefer.
I can't say I consider this good style, but I now recall there were
reasons (that I personally disagree with) for that style, though I don't
recall what those where.
Whether you choose to to inline it or not, please do it consistently.
(I know this doesn't quite answer the implicit question, but I don't
have an answer.)
Best regards,
Maxime Devos
[-- Attachment #1.1.2: OpenPGP public key --]
[-- Type: application/pgp-keys, Size: 929 bytes --]
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 236 bytes --]
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2023-10-17 20:41 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-09-06 14:06 [PATCH] doc: Extend documentation for (ice-9 match) Tomas Volf
2023-09-19 22:57 ` Maxime Devos
2023-10-15 17:40 ` Tomas Volf
2023-10-17 20:41 ` 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).