1
Fork 0
mirror of https://git.savannah.gnu.org/git/guile.git synced 2025-06-29 22:40:34 +02:00

Convert srfi-197.html to texinfo and add to srfi-modules.texi

Thanks to Maxim Cournoyer for reviewing these and the earlier SRFI-197
related changes and suggesting improvements.

* doc/ref/srfi-197.html: delete.
* doc/ref/srfi-modules.texi: integrate texinfo conversion of html.
This commit is contained in:
Rob Browning 2025-04-11 12:55:10 -05:00
parent 36ba0aa655
commit af0123c8b9
3 changed files with 317 additions and 120 deletions

View file

@ -29,6 +29,7 @@ Additionally, the documentation of the SRFI 64 module is adapted from
its specification text, which is made available under the following its specification text, which is made available under the following
Expat license: Expat license:
@quotation
Permission is hereby granted, free of charge, to any person obtaining a Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including "Software"), to deal in the Software without restriction, including
@ -47,6 +48,32 @@ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@end quotation
Additionally, the documentation of the SRFI 197 module is adapted from
its specification text, which is made available under the following
MIT license:
@quotation
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@end quotation
@end copying @end copying

File diff suppressed because one or more lines are too long

View file

@ -67,6 +67,7 @@ get the relevant SRFI documents from the SRFI home page
* SRFI-111:: Boxes. * SRFI-111:: Boxes.
* SRFI-119:: Wisp: simpler indentation-sensitive Scheme. * SRFI-119:: Wisp: simpler indentation-sensitive Scheme.
* SRFI-171:: Transducers * SRFI-171:: Transducers
* SRFI-197:: Pipeline operators
@end menu @end menu
@ -7079,6 +7080,295 @@ The generator version of list-reduce. It reduces over @code{gen} until
it returns the EOF object it returns the EOF object
@end deffn @end deffn
@node SRFI-197
@subsection SRFI-197: Pipeline Operators
@cindex SRFI-197
@cindex pipeline operators
@uref{http://srfi.schemers.org/srfi-197/srfi-197.html, SRFI-197}
provides functional pipeline (threading) operators like Clojure's
@code{->} or OCaml's @code{|>}. Pipelines are a simple, terse, and
readable way to write deeply-nested expressions. This SRFI defines a
family of chain and nest pipeline operators, which can rewrite nested
expressions like @code{(a b (c d (e f g)))} as a sequence of operations:
@code{(chain g (e f _) (c d _) (a b _))}.
Note that Like @code{let*}, @code{chain} guarantees evaluation order. In
fact, @code{(chain a (b _) (c _))} expands to something like @code{(let*
((x (b a)) (x (c x))) x)}, not @code{(c (b a))}, and so @code{chain} is
not suitable for pipelines containing syntax like @code{if} or
@code{let}.
For pipelines containing complex syntax, the @code{nest} and
@code{nest-reverse} operators look like @code{chain} but are guaranteed
to expand to nested forms, not @code{let*} forms. @code{nest} nests in
the opposite direction of @code{chain}, so @code{(nest (a _) (b _) c)}
expands to @code{(a (b c))}.
@deffn {Scheme Syntax} chain initial-value [placeholder [ellipsis]] step @dots{}
Converts earch @var{part} into a sequence of small integers and returns
a bytevector of the corresponding bytes as follows:
@var{initial-value} is an expression.
@var{placeholder} and @var{ellipsis} are literal symbols; these are the
placeholder symbol and ellipsis symbol. If @var{placeholder} or
@var{ellipsis} are not present, they default to @code{_} and @code{...},
respectively.
The syntax of @var{step} is (@var{datum} @dots{}), where each @var{datum} is
either the placeholder symbol, the ellipsis symbol, or an expression. A
@var{step} must contain at least one @var{datum}. The ellipsis symbol is
only allowed at the end of a @var{step}, and it must immediately follow
a placeholder symbol.
Semantics: @code{chain} evaluates each @var{step} in order from left to right,
passing the result of each step to the next.
Each @var{step} is evaluated as an application, and the return value(s)
of that application are passed to the next step as its pipeline
values. @var{initial-value} is the pipeline value of the first step. The
return value(s) of @code{chain} are the return value(s) of the last step.
The placeholder symbols in each @var{step} are replaced with that step's
pipeline values, in the order they appear. It is an error if the number
of placeholders for a step does not equal the number of pipeline values
for that step, unless the step contains no placeholders, in which case
it will ignore its pipeline values.
@lisp
(chain x (a b _))
@result{} (a b x)
(chain (a b) (c _ d) (e f _))
@result{} (let* ((x (a b)) (x (c x d))) (e f x))
(chain (a) (b _ _) (c _))
@result{} (let*-values (((x1 x2) (a)) ((x) (b x1 x2))) (c x))
@end lisp
If a @var{step} ends with a placeholder symbol followed by an ellipsis
symbol, that placeholder sequence is replaced with all remaining
pipeline values that do not have a matching placeholder.
@lisp
(chain (a) (b _ c _ ...) (d _))
@result{} (let*-values (((x1 . x2) (a)) ((x) (apply b x1 c x2))) (d x))
@end lisp
@code{chain} and all other SRFI 197 macros support custom placeholder
symbols, which can help to preserve hygiene when used in the body of a
syntax definition that may insert a @code{_} or @code{....}
@lisp
(chain (a b) <> (c <> d) (e f <>))
@result{} (let* ((x (a b)) (x (c x d))) (e f x))
(chain (a) - --- (b - c - ---) (d -))
@result{} (let*-values (((x1 . x2) (a)) ((x) (apply b x1 c x2))) (d x))
@end lisp
@end deffn
@deffn {Scheme Syntax} chain-and initial-value [placeholder] step @dots{}
@var{initial-value} is an expression. @var{placeholder} is a literal
symbol; this is the placeholder symbol. If @var{placeholder} is not
given, the placeholder symbol is @code{_}. The syntax of @var{step} is
(@var{datum} @dots{} [@var{placeholder} @var{datum} @dots{}]).
Semantics: A variant of @code{chain} that short-circuits and returns
@code{#f} if any step returns @code{#f}. @code{chain-and} is to
@code{chain} as SRFI 2 @code{and-let*} is to @code{let*}.
Each @var{step} is evaluated as an application. If the step evaluates to
@code{#f}, the remaining steps are not evaluated, and @code{chain-and}
returns #f. Otherwise, the return value of the step is passed to the
next step as its pipeline value. @var{initial-value} is the pipeline
value of the first step. If no step evaluates to @code{#f}, the return
value of @code{chain-and} is the return value of the last step.
The @var{placeholder} placeholder in each @var{step} is replaced with
that step's pipeline value. If a @var{step} does not contain
@var{placeholder}, it will ignore its pipeline value, but
@code{chain-and} will still check whether that pipeline value is
@code{#f}.
Because @code{chain-and} checks the return value of each step, it does
not support steps with multiple return values. It is an error if a step
returns more than one value.
@end deffn
@deffn {Scheme Syntax} chain-when initial-value [placeholder] ([guard] step) @dots{}
@var{initial-value} and @var{guard} are expressions. @var{placeholder}
is a literal symbol; this is the placeholder symbol. If
@var{placeholder} is not present, the placeholder symbol is
@code{_}. The syntax of @var{step} is (@var{datum} @dots{}
[@var{placeholder} @var{datum} @dots{}]).
Semantics: A variant of @code{chain} in which each step has a guard
expression and will be skipped if the guard expression evaluates to #f.
@lisp
(define (describe-number n)
(chain-when '()
((odd? n) (cons "odd" _))
((even? n) (cons "even" _))
((zero? n) (cons "zero" _))
((positive? n) (cons "positive" _))))
(describe-number 3) ; => '("positive" "odd")
(describe-number 4) ; => '("positive" "even")
@end lisp
Each @var{step} is evaluated as an application. The return value of the
step is passed to the next step as its pipeline
value. @var{initial-value} is the pipeline value of the first step.
The @var{placeholder} placeholder in each @var{step} is replaced with
that step's pipeline value. If a @var{step} does not contain
@var{placeholder}, it will ignore its pipeline value.
If a step's @var{guard} is present and evaluates to @code{#f}, that step
will be skipped, and its pipeline value will be reused as the pipeline
value of the next step. The return value of @code{chain-when} is the
return value of the last non-skipped step, or @var{initial-value} if all
steps are skipped.
Because @code{chain-when} may skip steps, it does not support steps with
multiple return values. It is an error if a step returns more than one
value.
@end deffn
@deffn {Scheme Syntax} chain-lambda [placeholder [ellipsis]] step @dots{}
@var{placeholder} and @var{ellipsis} are literal symbols; these are the
placeholder symbol and ellipsis symbol. If @var{placeholder} or
@var{ellipsis} are not present, they default to @code{_} and @code{...},
respectively.
The syntax of @var{step} is (@var{datum} @dots{}), where each
@var{datum} is either the placeholder symbol, the ellipsis symbol, or an
expression. A @var{step} must contain at least one @var{datum}. The
ellipsis symbol is only allowed at the end of a @var{step}, and it must
immediately follow a placeholder symbol.
Semantics: Creates a procedure from a sequence of @code{chain}
steps. When called, a @code{chain-lambda} procedure evaluates each
@var{step} in order from left to right, passing the result of each step
to the next.
@lisp
(chain-lambda (a _) (b _))
@result{} (lambda (x) (let* ((x (a x))) (b x)))
(chain-lambda (a _ _) (b c _))
@result{} (lambda (x1 x2) (let* ((x (a x1 x2))) (b c x)))
@end lisp
Each @var{step} is evaluated as an application, and the return value(s)
of that application are passed to the next step as its pipeline
values. The procedure's arguments are the pipeline values of the first
step. The return value(s) of the procedure are the return value(s) of
the last step.
The placeholder symbols in each @var{step} are replaced with that step's
pipeline values, in the order they appear. It is an error if the number
of placeholders for a step does not equal the number of pipeline values
for that step, unless the step contains no placeholders, in which case
it will ignore its pipeline values.
If a @var{step} ends with a placeholder symbol followed by an ellipsis
symbol, that placeholder sequence is replaced with all remaining
pipeline values that do not have a matching placeholder.
The number of placeholders in the first @var{step} determines the arity
of the procedure. If the first step ends with an ellipsis symbol, the
procedure is variadic.
@end deffn
@deffn {Scheme Syntax} nest [placeholder] <step> @dots{} initial-value
@var{placeholder} is a literal symbol; this is the placeholder
symbol. If @var{placeholder} is not present, the placeholder symbol is
@code{_}. The syntax of @var{step} is (@var{datum} @dots{}
@var{placeholder} @var{datum} @dots{}). @var{initial-value} is an
expression.
Semantics: @code{nest} is similar to @code{chain}, but sequences its
steps in the opposite order. Unlike @code{chain}, @code{nest} literally
nests expressions; as a result, it does not provide the same strict
evaluation order guarantees as @code{chain}.
@lisp
(nest (a b _) (c d _) e) ; => (a b (c d e))
@end lisp
A @code{nest} expression is evaluated by lexically replacing the
@var{placeholder} in the last @var{step} with @var{initial-value}, then
replacing the @var{placeholder} in the next-to-last @var{step} with that
replacement, and so on until the @var{placeholder} in the first
@var{step} has been replaced. It is an error if the resulting final
replacement is not an expression, which is then evaluated and its values
are returned.
Because it produces an actual nested form, @code{nest} can build
expressions that @code{chain} cannot. For example, @code{nest} can build
a quoted data structure:
@lisp
(nest '_ (1 2 _) (3 _ 5) (_) 4) ; => '(1 2 (3 (4) 5))
@end lisp
@code{nest} can also safely include special forms like if, let, lambda, or parameterize in a pipeline.
A custom placeholder can be used to safely nest @code{nest} expressions.
@lisp
(nest (nest _2 '_2 (1 2 3 _2) _ 6)
(_ 5 _2)
4)
@result{} '(1 2 3 (4 5 6))
@end lisp
@end deffn
@deffn {Scheme Syntax} nest-reverse initial-value [placeholder] step @dots{}
Syntax: @var{initial-value} is an expression. @var{placeholder} is a
literal symbol; this is the placeholder symbol. If @var{placeholder} is
not present, the placeholder symbol is @code{_}. The syntax of
@var{step} is (@var{datum} @dots{} @var{placeholder} @var{datum}
@dots{}).
Semantics: @code{nest-reverse} is variant of @code{nest} that nests in
reverse order, which is the same order as @code{chain}.
@lisp
(nest-reverse e (c d _) (a b _)) ; => (a b (c d e))
@end lisp
A @code{nest-reverse} expression is evaluated by lexically replacing the
@var{placeholder} in the first @var{step} with @var{initial-value}, then
replacing the @var{placeholder} in the second @var{step} with that
replacement, and so on until the @var{placeholder} in the last
@var{step} has been replaced. It is an error if the resulting final
replacement is not an expression, which is then evaluated and its values
are returned.
@end deffn
@subsubsection Acknowledgements
Thanks to the participants in the SRFI 197 mailing list who helped Adam
Nelson refine this SRFI, including Marc Nieper-Wißkirchen, Linus
Björnstam, Shiro Kawai, Lassi Kortela, and John Cowan.
Marc provided a paragraph that has been included (with only minor
changes) in the Semantics section of the nest and nest-reverse macros.
Thanks to Rich Hickey for @url{https://clojure.org, Clojure} and the
original implementation of Clojure threading macros, and to Paulus
Esterhazy for the (EPL licensed) threading macros documentation page,
which was a source of inspiration and some of the examples in this
document.
@c srfi-modules.texi ends here @c srfi-modules.texi ends here
@c Local Variables: @c Local Variables: