Re: How to abort a read from a socket after some time?

2024-01-22 Thread Tomas Volf
Hello,

thank you very much for the email and the suggested approach, I will try it out.
I just have one more question:

On 2024-01-22 00:46:23 +0100, M wrote:
> >
> > All code below runs after handler is set:
> >
> >(sigaction SIGALRM (lambda _ (display "Alarm!\n")))
>
> Assuming the read-char takes too long, the kernel sends a SIGALRM to Guile. 
> Hence, the C signal handler is run (which sets some fields somewhere 
> indicating that this handler should be run later in the sense of 
> system-async-mark), and the syscall behind read-char returns EINTR.
>
> As this is a fake error (passing it on as a Scheme exception would result in 
> rather messy semantics, e.g. consider the case where things are interrupted 
> twice in a row, time such that the exception handler itself is interrupted 
> with a new exception), Guile decides to retry the syscall

I am confused about this.  I read the documentation for sigaction, and there is
this text for the flags argument:

  -- Variable: SA_RESTART
  If a signal occurs while in a system call, deliver the signal
  then restart the system call (as opposed to returning an
  ‘EINTR’ error from that call).

Based on that my expectation was to get EINTR.  But since the syscall seems to
be restarted even without the SA_RESTART, what exactly does this flag do then?

Thank you,
Tomas Volf

--
There are only two hard things in Computer Science:
cache invalidation, naming things and off-by-one errors.


signature.asc
Description: PGP signature


[PATCH v2] Add more detailed instructions into the HACKING file.

2023-12-04 Thread Tomas Volf
Until now, the ./meta/guile was not mentioned anywhere, and therefore it
was not obvious how to run the locally compiled Guile without installing
it.

While modifying the file, I took the liberty to also mention a bit about
compiling Guile using Guix.

Finally, the header lines where cleaned up, ensuring all of them end at
70 and have a leading space.

* HACKING (Hacking It Yourself): Add Guix instructions.  Add a note
about meta/guile script.
(Sample GDB Initialization File),
(Naming conventions): Clean up the header line.
---
v2:
Add note regarding JIT and GNU Hurd.  Add note regarding -fexcess-precision.
Add --disable-static and explain it.

 HACKING | 38 --
 1 file changed, 36 insertions(+), 2 deletions(-)

diff --git a/HACKING b/HACKING
index 387643bf7..5926fb275 100644
--- a/HACKING
+++ b/HACKING
@@ -26,6 +26,40 @@ http://www.gnu.org/software/guile/mail/mail.html for more 
info.

 Hacking It Yourself ==

+You can spawn a shell with all the required dependencies using GNU Guix
+by running the following command:
+
+guix shell -D -f guix.scm --pure
+
+In this way, you can effortlessly compile Guile from the Git checkout
+with just these three lines:
+
+guix shell -D -f guix.scm --pure -- ./autogen.sh
+guix shell -D -f guix.scm --pure -- ./configure \
+--enable-mini-gmp --disable-static
+guix shell -D -f guix.scm --pure -- make
+
+Disabling of the static libraries is optional, but it does speed up the
+builds, and you are unlikely to need them for local development.
+
+  Note: Currently JIT causes Guile to crash in obscure ways on GNU Hurd,
+so on that platform you want to also pass the --disable-jit flag
+to the configure script.
+
+  Note: On any i*86 architecture, you also need to pass in the compiler
+flag -fexcess-precision=standard in order to get the test suite
+to pass.  That can be done by passing an additional argument to
+the configure script:
+ CFLAGS='-g -O2 -fexcess-precision=standard'
+
+Once that finishes, you can execute your newly compiled Guile using the
+./meta/guile script:
+
+$ ./meta/guile -v | head -n1
+guile (GNU Guile) 3.0.9.139-d7cf5-dirty
+
+For more manual approach, read on.
+
 When Guile is obtained from Git, a few extra steps must be taken
 before the usual configure, make, make install.  You will need to have
 up-to-date versions of the tools as listed below, correctly installed.
@@ -73,7 +107,7 @@ Here is the authoritative list of tool/version/platform 
tuples that
 have been known to cause problems, and a short description of the problem.


-Sample GDB Initialization File=
+Sample GDB Initialization File ===

 In GDB, you probably want to load the gdbinit file included with Guile,
 which defines a number of GDB helpers to inspect Scheme values.
@@ -215,7 +249,7 @@ The goal is to reduce (and over time, eliminate) spurious 
diffs.
 For Emacs users:
   (add-hook 'before-save-hook 'delete-trailing-whitespace)

-Naming conventions =
+Naming conventions ===

 We use certain naming conventions to structure the considerable number
 of global identifiers.  All identifiers should be either all lower
--
2.41.0



Re: [PATCH] Add more detailed instructions into the HACKING file.

2023-12-04 Thread Tomas Volf
Thank you for the review.

On 2023-12-04 22:06:42 +0100, Maxime Devos wrote:
>
>
> Op 29-11-2023 om 17:40 schreef Tomas Volf:
> > +guix shell -D -f guix.scm --pure -- ./configure --enable-mini-gmp
>
> Also -fexcess-precision=standard (see #49368 / #49659 on debbugs) (at least
> for i*86, should be harmless for other architectures though).

That explains why I did not catch it (I did run the test suite, but I am on
x86_64).

Out of curiosity, since it should be harmless elsewhere, is there a reason this
is not a flag set by default?

>
> Also --disable-jit when on the Hurd.
>
> You might want to check if static libraries are built by default (*), and if
> so, add --disable-static to reduce compilation time.
>
> (*) can be tested with "find . -name '*.a'" after "make" -- don't worry
> about libgnu.a, IIUC only libguile-3.0.a / .so is important.
>
> Best regards,
> Maxime Devos.

I added a note regarding the Hurd and the disabling of static libraries.

Will send v2.

Have a nice day,
Tomas Volf

--
There are only two hard things in Computer Science:
cache invalidation, naming things and off-by-one errors.


signature.asc
Description: PGP signature


[PATCH] Add more detailed instructions into the HACKING file.

2023-11-29 Thread Tomas Volf
Until now, the ./meta/guile was not mentioned anywhere, and therefore it
was not obvious how to run the locally compiled Guile without installing
it.

While modifying the file, I took the liberty to also mention a bit about
compiling Guile using Guix.

Finally, the header lines where cleaned up, ensuring all of them end at
70 and have a leading space.

* HACKING (Hacking It Yourself): Add Guix instructions.  Add a note
about meta/guile script.
(Sample GDB Initialization File),
(Naming conventions): Clean up the header line.
---
I think this will make it easier for people to start hacking on the Guile.

 HACKING | 24 ++--
 1 file changed, 22 insertions(+), 2 deletions(-)

diff --git a/HACKING b/HACKING
index 387643bf7..ae39218fa 100644
--- a/HACKING
+++ b/HACKING
@@ -26,6 +26,26 @@ http://www.gnu.org/software/guile/mail/mail.html for more 
info.

 Hacking It Yourself ==

+You can spawn a shell with all the required dependencies using GNU Guix
+by running the following command:
+
+guix shell -D -f guix.scm --pure
+
+In this way, you can effortlessly compile Guile from the Git checkout
+with just these three lines:
+
+guix shell -D -f guix.scm --pure -- ./autogen.sh
+guix shell -D -f guix.scm --pure -- ./configure --enable-mini-gmp
+guix shell -D -f guix.scm --pure -- make
+
+Once that finishes, you can execute your newly compiled Guile using the
+./meta/guile script:
+
+$ ./meta/guile -v | head -n1
+guile (GNU Guile) 3.0.9.139-d7cf5-dirty
+
+For more manual approach, read on.
+
 When Guile is obtained from Git, a few extra steps must be taken
 before the usual configure, make, make install.  You will need to have
 up-to-date versions of the tools as listed below, correctly installed.
@@ -73,7 +93,7 @@ Here is the authoritative list of tool/version/platform 
tuples that
 have been known to cause problems, and a short description of the problem.


-Sample GDB Initialization File=
+Sample GDB Initialization File ===

 In GDB, you probably want to load the gdbinit file included with Guile,
 which defines a number of GDB helpers to inspect Scheme values.
@@ -215,7 +235,7 @@ The goal is to reduce (and over time, eliminate) spurious 
diffs.
 For Emacs users:
   (add-hook 'before-save-hook 'delete-trailing-whitespace)

-Naming conventions =
+Naming conventions ===

 We use certain naming conventions to structure the considerable number
 of global identifiers.  All identifiers should be either all lower
--
2.41.0



[PATCH] Add copy-on-write support to scm_copy_file.

2023-11-29 Thread Tomas Volf
On modern file-systems (BTRFS, ZFS) it is possible to copy a file using
copy-on-write method.  For large files it has the advantage of being
much faster and saving disk space (since identical extents are not
duplicated).  This feature is stable and for example coreutils' `cp'
does use it automatically (see --reflink).

This commit adds support for this feature into our
copy-file (scm_copy_file) procedure.  Same as `cp', it defaults to
'auto, meaning the copy-on-write is attempted, and in case of failure
the regular copy is performed.

No tests are provided, because the behavior depends on the system,
underlying file-system and its configuration.  That makes it challenging
to write a test for it.  Manual testing was performed instead:

$ btrfs filesystem du /tmp/cow*
 Total   Exclusive  Set shared  Filename
  36.00KiB36.00KiB   0.00B  /tmp/cow

$ cat cow-test.scm
(copy-file "/tmp/cow" "/tmp/cow-unspecified")
(copy-file "/tmp/cow" "/tmp/cow-always" #:copy-on-write 'always)
(copy-file "/tmp/cow" "/tmp/cow-auto" #:copy-on-write 'auto)
(copy-file "/tmp/cow" "/tmp/cow-never" #:copy-on-write 'never)
(copy-file "/tmp/cow" "/dev/shm/cow-unspecified")
(copy-file "/tmp/cow" "/dev/shm/cow-auto" #:copy-on-write 'auto)
(copy-file "/tmp/cow" "/dev/shm/cow-never" #:copy-on-write 'never)
$ ./meta/guile -s cow-test.scm

$ btrfs filesystem du /tmp/cow*
 Total   Exclusive  Set shared  Filename
  36.00KiB   0.00B36.00KiB  /tmp/cow
  36.00KiB   0.00B36.00KiB  /tmp/cow-always
  36.00KiB   0.00B36.00KiB  /tmp/cow-auto
  36.00KiB36.00KiB   0.00B  /tmp/cow-never
  36.00KiB   0.00B36.00KiB  /tmp/cow-unspecified

$ sha1sum /tmp/cow* /dev/shm/cow*
4c665f87b5dc2e7d26279c4b48968d085e1ace32  /tmp/cow
4c665f87b5dc2e7d26279c4b48968d085e1ace32  /tmp/cow-always
4c665f87b5dc2e7d26279c4b48968d085e1ace32  /tmp/cow-auto
4c665f87b5dc2e7d26279c4b48968d085e1ace32  /tmp/cow-never
4c665f87b5dc2e7d26279c4b48968d085e1ace32  /tmp/cow-unspecified
4c665f87b5dc2e7d26279c4b48968d085e1ace32  /dev/shm/cow-auto
4c665f87b5dc2e7d26279c4b48968d085e1ace32  /dev/shm/cow-never
4c665f87b5dc2e7d26279c4b48968d085e1ace32  /dev/shm/cow-unspecified

This commit also adds to new failure modes for (copy-file).

Failure to copy-on-write when 'always was passed in:

scheme@(guile-user)> (copy-file "/tmp/cow" "/dev/shm/cow" #:copy-on-write 
'always)
ice-9/boot-9.scm:1676:22: In procedure raise-exception:
In procedure copy-file: copy-on-write failed: Invalid cross-device link

Passing in invalid value for the #:copy-on-write keyword argument:

scheme@(guile-user)> (copy-file "/tmp/cow" "/dev/shm/cow" #:copy-on-write 
'nevr)
ice-9/boot-9.scm:1676:22: In procedure raise-exception:
In procedure copy-file: invalid value for #:copy-on-write: nevr

* NEWS: Add note for copy-file supporting copy-on-write.
* configure.ac: Check for linux/fs.h.
* doc/ref/posix.texi (File System)[copy-file]: Document the new
signature.
* libguile/filesys.c (clone_file): New function cloning a file using
FICLONE, if supported.
(k_copy_on_write): New keyword.
(sym_always, sym_auto, sym_never): New symbols.
(scm_copy_file): New #:copy-on-write keyword argument.  Attempt
copy-on-write copy by default.
* libguile/filesys.h: Update signature for scm_copy_file.
---
My first C patch to Guile.  I am not used to the GNU coding style, so I
apologize in advance if I got something wrong.  I tried.

I believe the 'auto is correct default, mimicking how coreutils' cp works.

 NEWS   |  9 ++
 configure.ac   |  1 +
 doc/ref/posix.texi |  9 +-
 libguile/filesys.c | 74 +++---
 libguile/filesys.h |  2 +-
 5 files changed, 82 insertions(+), 13 deletions(-)

diff --git a/NEWS b/NEWS
index b319404d7..9147098c9 100644
--- a/NEWS
+++ b/NEWS
@@ -21,6 +21,15 @@ definitely unused---this is notably the case for modules 
that are only
 used at macro-expansion time, such as (srfi srfi-26).  In those cases,
 the compiler reports it as "possibly unused".

+** copy-file now supports copy-on-write
+
+The copy-file procedure now takes an additional keyword argument,
+#:copy-on-write, specifying whether copy-on-write should be done, if the
+underlying file-system supports it.  Possible values are 'always, 'auto
+and 'never, with 'auto being the default.
+
+This speeds up copying large files a lot while saving the disk space.
+
 * Bug fixes

 ** (ice-9 suspendable-ports) incorrect UTF-8 decoding
diff --git a/configure.ac b/configure.ac
index d0a2dc79b..c46586e9b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -418,6 +418,7 @@ AC_SUBST([SCM_I_GSC_HAVE_STRUCT_DIRENT64])
 #   sys/sendfile.h - non-POSIX, found in glibc
 #
 AC_CHECK_HEADERS([complex.h fenv.h io.h memory.h process.h \
+linux/fs.h \
 sys/dir.h sys/ioctl.h sys/select.h \
 sys/time.h sys/timeb.h sys/times.h sys/stdtypes.h 

[PATCH] doc: Fix example in list-transduce example.

2023-11-28 Thread Tomas Volf
While the `.' might be correct from a grammatical point of view (I do
not know), it turns the example into invalid scheme code, which is not
ideal.  New users (like me) might try to copy the whole line and wonder
why it does not work (like I did).  So delete it.

* doc/ref/srfi-modules.texi (SRFI-171 General Discussion): Delete the
trailing . from the example.
---
 doc/ref/srfi-modules.texi | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/doc/ref/srfi-modules.texi b/doc/ref/srfi-modules.texi
index 0cdf56923..09b591e89 100644
--- a/doc/ref/srfi-modules.texi
+++ b/doc/ref/srfi-modules.texi
@@ -5748,7 +5748,7 @@ reducer with result-so-far and the maybe-transformed 
input.
 A simple example is as following:
 
 @example
-(list-transduce (tfilter odd?) + '(1 2 3 4 5)).
+(list-transduce (tfilter odd?) + '(1 2 3 4 5))
 @end example
 
 This first returns a transducer filtering all odd
-- 
2.41.0




[PATCH v3] doc: Extend documentation for (ice-9 match)

2023-11-28 Thread Tomas Volf
Extend the documentation for (ice-9 match) module with explanations 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.
---
v2:
* drop myself from THANKS file, someone else can thank me if they want to
* remove most of unnecessary lets
* spelling and wording fixes
* add new paragraph describing (and ...)

v3:
Attempt to resolve feedback regarding the let usage:

> Whether you choose to to inline it or not, please do it consistently.

I removed all of them except two.  The very first one, since in this case I
believe it leads to the comments being more readable:

(let ((l '(hello (world
  (match l   ;; <- the input object
(('hello (who))  ;; <- the pattern
 who)))  ;; <- the expression evaluated upon matching

It also creates a nice contrast with the second example, which now also
demonstrates that you do not have to use the let, and the object can be inline.

Second case is the "more complex example", where I believe the let again leads
to significantly more readable code (keeping alice and bob together) to outweigh
the perceived inconsistency.

If requested, I can of course nuke these two usages as well.

 doc/ref/match.texi | 90 +++---
 1 file changed, 86 insertions(+), 4 deletions(-)

diff --git a/doc/ref/match.texi b/doc/ref/match.texi
index f5ea43118..774fc856e 100644
--- a/doc/ref/match.texi
+++ b/doc/ref/match.texi
@@ -50,10 +50,9 @@ list---i.e., the symbol @code{world}.  An error would be 
raised if
 The same object can be matched against a simpler pattern:
 
 @example
-(let ((l '(hello (world
-  (match l
-((x y)
- (values x y
+(match '(hello (world))
+  ((x y)
+   (values x y)))
 @result{} hello
 @result{} (world)
 @end example
@@ -181,6 +180,89 @@ 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, the pattern @code{string} binds the
+value to the identifier @code{string} and the pattern @code{"string"}
+matches if the value is @code{"string"}.  An example demonstrating this
+(by using very bad naming):
+
+@example
+(match "foo"
+  (number number))
+@result{} "foo"
+@end example
+
+The field operator (@code{(= field pat)}) has no relation to the fields
+of 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
+(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 records.  Patterns are matched against the slots in order,
+not all have to be present, and there is no way to skip a slot.  An
+example demonstrating the usage:
+
+@example
+(define-record-type 
+  (make-foo bar baz zab)
+  foo?
+  (bar foo-bar)
+  (baz foo-baz)
+  (zab foo-zab))
+
+(match (make-foo 1 '2 "three")
+  ;; Make sure obj is a  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.
+  (($  (? 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 as if in the @code{(and ...)}.  If, for example, you want
+to check whether something is a symbol and at the same time bind the
+value to a variable, it could look like this:
+
+@example
+(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
+
+The @code{(and ...)} is of course useful as well, especially if no
+predicate is required.  While you could use @code{(const #t)} as the
+predicate, using @code{(and ...)} is better.  For example, capturing an
+object iff it is a list of at least two items can be done like this:
+
+@example
+(match '(foo baz bar)
+  ((and (a b ...) lst)
+   lst))
+@result{} (foo baz bar)
+@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 

[PATCH v2] doc: Extend documentation for (ice-9 match)

2023-10-15 Thread Tomas Volf
Extend the documentation for (ice-9 match) module with explanations 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.
---
Incorporate feedback from the review, mainly:
- drop myself from THANKS file, someone else can thank me if they want to
- remove most of unnecessary lets
- spelling and wording fixes
- add new paragraph describing (and ...)

 doc/ref/match.texi | 84 ++
 1 file changed, 84 insertions(+)

diff --git a/doc/ref/match.texi b/doc/ref/match.texi
index f5ea43118..6e43d59b1 100644
--- a/doc/ref/match.texi
+++ b/doc/ref/match.texi
@@ -181,6 +181,90 @@ 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, the pattern @code{string} binds the
+value to the identifier @code{string} and the pattern @code{"string"}
+matches if the value is @code{"string"}.  An example demonstrating this
+(by using very bad naming):
+
+@example
+(match "foo"
+  (number number))
+@result{} "foo"
+@end example
+
+The field operator (@code{(= field pat)}) has no relation to the fields
+of 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
+(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 records.  Patterns are matched against the slots in order,
+not all have to be present, and there is no way to skip a slot.  An
+example demonstrating the usage:
+
+@example
+(define-record-type 
+  (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  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.
+(($  (? 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 as if in the @code{(and ...)}.  If, for example, you want
+to check whether something is a symbol and at the same time bind the
+value to a variable, it could look like this:
+
+@example
+(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
+
+The @code{(and ...)} is of course useful as well, especially if no
+predicate is required.  While you could use @code{(const #t)} as the
+predicate, using @code{(and ...)} is better.  For example, capturing an
+object iff it is a list of at least two items can be done like this:
+
+@example
+(match '(foo baz bar)
+  ((and (a b ...) lst)
+   lst))
+@result{} (foo baz bar)
+@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




Re: [PATCH] doc: Extend documentation for (ice-9 match)

2023-10-15 Thread Tomas Volf
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)))
>

[PATCH] doc: Extend documentation for (ice-9 match)

2023-09-06 Thread 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 
+  (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  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.
+(($  (? 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