404 lines
16 KiB
HTML
404 lines
16 KiB
HTML
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
|
|
<html>
|
|
<head>
|
|
<title>SRFI 26: Notation for Specializing Parameters without Currying</title>
|
|
</head>
|
|
|
|
<body>
|
|
|
|
<H1>Title</H1>
|
|
|
|
SRFI 26: Notation for Specializing Parameters without Currying
|
|
|
|
<H1>Author</H1>
|
|
|
|
Sebastian Egner
|
|
|
|
<H1>Status</H1>
|
|
|
|
This SRFI is currently in ``final'' status. To see an explanation of
|
|
each status that a SRFI can hold, see <a
|
|
href="http://srfi.schemers.org/srfi-process.html">here</a>. You can access
|
|
the discussion via
|
|
<a href="http://srfi.schemers.org/srfi-26/mail-archive/maillist.html">
|
|
the archive of the mailing list</a>.
|
|
|
|
<UL>
|
|
<LI>Draft: 2002/02/06-2002/04/06 </LI>
|
|
<LI>Revised: 2002/02/15</LI>
|
|
<LI>Revised: 2002/02/28</LI>
|
|
<LI>Revised: 2002/06/04</LI>
|
|
<LI>Revised: 2002/06/06</LI>
|
|
<LI>Final: 2002/06/14</LI>
|
|
</UL>
|
|
|
|
<H1>Abstract</H1>
|
|
|
|
When programming in functional style,
|
|
it is frequently necessary to specialize some of the
|
|
parameters of a multi-parameter procedure.
|
|
For example, from the binary operation <code>cons</code>
|
|
one might want to obtain the unary operation
|
|
<code>(lambda (x) (cons 1 x))</code>.
|
|
This specialization of parameters is also known as
|
|
"partial application", "operator section" or "projection".<p>
|
|
|
|
The mechanism proposed here allows to write this sort
|
|
of specialization in a simple and compact way.
|
|
The mechanism is best explained by a few examples:<p>
|
|
|
|
<TABLE>
|
|
<TR>
|
|
<TD><code>(cut cons (+ a 1) <>)</code>
|
|
<TD>is the same as
|
|
<TD><code>(lambda (x2) (cons (+ a 1) x2))</code>
|
|
</TR>
|
|
<TR>
|
|
<TD><code>(cut list 1 <> 3 <> 5)</code>
|
|
<TD>is the same as
|
|
<TD><code>(lambda (x2 x4) (list 1 x2 3 x4 5))</code>
|
|
</TR>
|
|
<TR>
|
|
<TD><code>(cut list)</code>
|
|
<TD>is the same as
|
|
<TD><code>(lambda () (list))</code>
|
|
</TR>
|
|
<TR>
|
|
<TD><code>(cut list 1 <> 3 <...>)</code>
|
|
<TD>is the same as
|
|
<TD><code>(lambda (x2 . xs) (apply list 1 x2 3 xs))</code>
|
|
</TR>
|
|
<TR>
|
|
<TD><code>(cut <> a b)</code>
|
|
<TD>is the same as
|
|
<TD><code>(lambda (f) (f a b))</code>
|
|
</TR>
|
|
</TABLE><p>
|
|
|
|
As you see, the macro <code>cut</code> specializes some of the
|
|
parameters of its first argument.
|
|
The parameters that are to show up as formal
|
|
variables of the result are indicated by the symbol <code><></code>,
|
|
pronouced as "slot". In addition, the symbol <code><...></code>,
|
|
pronounced as "rest-slot", matches all residual arguments of a variable
|
|
argument procedure.
|
|
As you can see from the last example above, the first argument can also
|
|
be a slot, as one should expect in Scheme.<p>
|
|
|
|
In addition to <code>cut</code>, there is a variant called <code>cute</code>
|
|
(a mnemonic for "<code>cut</code> with evaluated non-slots") which evaluates
|
|
the non-slot expressions at the time the procedure is specialized, not at
|
|
the time the specialized procedure is called.
|
|
For example,<p>
|
|
|
|
<TABLE>
|
|
<TR>
|
|
<TD><code>(cute cons (+ a 1) <>)</code>
|
|
<TD>is the same as
|
|
<TD><code>(let ((a1 (+ a 1))) (lambda (x2) (cons a1 x2)))</code>
|
|
</TR>
|
|
</TABLE><p>
|
|
|
|
As you see from comparing this example with the first example above,
|
|
the <code>cute</code>-variant will evaluate <code>(+ a 1)</code>
|
|
once, while the <code>cut</code>-variant will evaluate it during
|
|
every invokation of the resulting procedure.<p>
|
|
|
|
The mechanism proposed in this SRFI allows specializing any subset
|
|
of the variables of a procedure.
|
|
The result can be of fixed arity or of variable arity.
|
|
The mechanism does not allow permutation, omission, duplication
|
|
or any other processing of the arguments;
|
|
for this it is necessary to write to use a different
|
|
mechanism such as <code>lambda</code>.
|
|
|
|
<H1>Rationale</H1>
|
|
|
|
A particularly elegant way to deal with specialization is known
|
|
as <em>currying</em> (Schönfinkel 1924, Curry 1958).
|
|
The idea of currying is to reduce multi-argument functions to
|
|
single-argument functions by regarding an <i>n</i>-ary
|
|
function as a unary function mapping its first argument into
|
|
an (<i>n</i>-1)-ary function (which is curried in turn).
|
|
This point of view, apart from its theoretical elegance,
|
|
allows an extremely compact notation for specializing the
|
|
first argument of a function.
|
|
In the first example, one could simply write <code>(cons 1)</code>.<p>
|
|
|
|
Yet, Scheme is not a curried language---the
|
|
number of arguments passed to a procedure must match
|
|
the number of its parameters at all times.
|
|
This allows zero- and variable-arity procedures
|
|
but in order to specialize parameters
|
|
one usually has to write down a lambda-expression
|
|
and invent some irrelevant identifiers for its
|
|
formal variables (<code>x</code> in the example).
|
|
For this reason, the mechanism proposed in this SRFI
|
|
provides a simple and compact notation for specializing
|
|
any subset of the parameters of a procedure.<p>
|
|
|
|
Note: <em>The mechanism proposed here is not currying!</em><p>
|
|
|
|
The purpose of the mechanism proposed here is to make the benefits
|
|
of currying available within the programming language Scheme.
|
|
There are two primary benefits of currying in practice:
|
|
Higher-order types are substantially simplified and
|
|
there is a simple notation for specializing parameters.
|
|
The type aspect is irrelevant as Scheme has latent typing.
|
|
The specialization aspect is largly covered with this SRFI.<p>
|
|
|
|
Here are a few more examples for illustration:
|
|
|
|
<TABLE>
|
|
<TR>
|
|
<TD><code>(map (cut * 2 <>) '(1 2 3 4))</code>
|
|
</TR>
|
|
<TR>
|
|
<TD><code>(map (cut vector-set! x <> 0) indices)</code>
|
|
</TR>
|
|
<TR>
|
|
<TD><code>(for-each (cut write <> port) exprs)</code>
|
|
</TR>
|
|
<TR>
|
|
<TD><code>(map (cut <> x y z) (list min max))</code>
|
|
</TR>
|
|
<TR>
|
|
<TD><code>(for-each (cut <>) thunks)</code>
|
|
</TR>
|
|
</TABLE>
|
|
|
|
<H1>Specification</H1>
|
|
|
|
<a name="cut"></a><a name="cute"></a>
|
|
The formal syntax of a specialized expression, in the style of the
|
|
<a href="http://www.schemers.org/Documents/Standards/R5RS/"><I>Revised^5 Report on the Algorithmic Language Scheme</I></a>:<p>
|
|
|
|
<TABLE>
|
|
<TR>
|
|
<TD><a name="cut"></a><a name="cute"></a><code><cut-expression></code>
|
|
<TD><code>--></code>
|
|
<TD><TD><code>(cut <slot-or-expr> <slot-or-expr>*)</code>
|
|
<TD>
|
|
</TR>
|
|
<TR>
|
|
<TD><TD><TD>|<TD><code>(cut <slot-or-expr> <slot-or-expr>* <...>)</code>
|
|
<TD>; with "rest-slot"
|
|
</TR>
|
|
<TR>
|
|
<TD><TD><TD>|<TD><code>(cute <slot-or-expr> <slot-or-expr>*)</code>
|
|
<TD>; evaluate non-slots at specialization time
|
|
</TR>
|
|
<TR>
|
|
<TD><TD><TD>|<TD><code>(cute <slot-or-expr> <slot-or-expr>* <...>)</code>
|
|
<TD>; with "rest-slot"
|
|
</TR>
|
|
<TR>
|
|
<TD><code><slot-or-expr></code>
|
|
<TD><code>--></code>
|
|
<TD><TD><code><></code><TD>; a "slot"
|
|
</TR>
|
|
<TR>
|
|
<TD><TD><TD>|<TD> <code><expression></code><TD>; a "non-slot expression"
|
|
</TR>
|
|
</TABLE><p>
|
|
|
|
The macro <code>cut</code> transforms a <code><cut-expression></code>
|
|
into a <code><lambda expression></code> with as many formal variables
|
|
as there are slots in the list <code><slot-or-expr>*</code>.
|
|
The body of the resulting <code><lambda expression></code> calls
|
|
the first <code><slot-or-expr></code> with arguments from
|
|
<code><slot-or-expr>*</code> in the order they appear.
|
|
In case there is a rest-slot symbol, the resulting procedure is also of
|
|
variable arity, and the body calls the first <code><slot-or-expr></code>
|
|
with all arguments provided to the actual call of the specialized procedure.<p>
|
|
|
|
The macro <code>cute</code> is similar to the macro <code>cut</code>,
|
|
except that it first binds new variables to the result of evaluating
|
|
the non-slot expressions (in an unspecific order) and then substituting
|
|
the variables for the non-slot expressions.
|
|
In effect, <code>cut</code> evaluates non-slot expressions at the time
|
|
the resulting procedure is called, whereas <code>cute</code> evaluates
|
|
the non-slot expressions at the time the procedure is constructed.<p>
|
|
|
|
<H1>Implementation</H1>
|
|
|
|
The reference implementation defines the two macros
|
|
<code>cut</code> and <code>cute</code> using macro
|
|
mechanism of R5RS.
|
|
It does not use any other SRFI or any library.
|
|
The implementation makes use of internal macros to
|
|
run through the list of <code><slot-or-expr;></code>s.
|
|
As macros in R5RS are hygienic and referentially transparent,
|
|
the macro mechanism makes sure the names of the newly
|
|
introduced formal variables are unique and do not clash.
|
|
The template <code>(param ... slot)</code>, see
|
|
<a href="http://www.schemers.org/Documents/Standards/R5RS/HTML/r5rs-Z-H-10.html#%_sec_7.1.5">Sect. 7.1.5. of R5RS</a>,
|
|
allows to preserve the order of arguments---which would get
|
|
reversed otherwise.
|
|
|
|
The reference implementation has been written by
|
|
Al Petrofsky. It can be found <a href="http://srfi.schemers.org/srfi-26/cut.scm">here</a>.<p>
|
|
|
|
Finally, there is a small collection of
|
|
<a href="http://srfi.schemers.org/srfi-26/check.scm">confidence tests</a>.
|
|
It checks some special cases of the mechanism defined
|
|
in this SRFI and signals an error in case something is wrong.
|
|
Passing the tests does not mean a correct implementation.
|
|
|
|
|
|
<H1>Design Rationale</H1>
|
|
|
|
<H3>Why not real currying/uncurrying?</H3>
|
|
|
|
It is possible in Scheme to implement a macro turning a multi-argument
|
|
procedure into a nesting of single-argument procedures and back.
|
|
These operations are usually called "curry" and "uncurry" in
|
|
other programming languages.
|
|
Yet, Scheme remains an inherently uncurried language and is not
|
|
prepared to deal with curried procedures in a convenient way.
|
|
Hence, a "by the book" implementation of currying would only be useful
|
|
if you apply it in the sequence "curry, specialize some arguments,
|
|
and uncurry again"---which is exactly the purpose of the macro
|
|
<code>cut</code> specified in this document.
|
|
The primary relevance of currying/uncurrying in Scheme is to
|
|
teach concepts of combinatory logic.<p>
|
|
|
|
<H3>Why not a more general mechanism, also allowing permutation,
|
|
omission and duplication of arguments?</H3>
|
|
|
|
The reason is that I, the author of this SRFI, consider more general
|
|
mechanisms too dangerous to mix them with the mechanism proposed here.
|
|
In particular, as soon as parameters are being rearranged it
|
|
is usually necessary to be aware of the meaning of the parameters;
|
|
unnamed variables can be quite harmful then.
|
|
The mechanism proposed here is designed to prevent this.
|
|
Please refer to the discussion threads
|
|
<a href="http://srfi.schemers.org/srfi-26/mail-archive/msg00018.html">"OK, how about...,"</a> (Alan Bawden),
|
|
<a href="http://srfi.schemers.org/srfi-26/mail-archive/msg00038.html">"is that useful?"</a> (Walter C. Pelissero), and
|
|
<a href="http://srfi.schemers.org/srfi-26/mail-archive/msg00040.html">"l, the ultimate curry that is not curry"</a> (Al Petrofsky).<p>
|
|
|
|
<H3>Why are the macro called <code>cut/cute</code> and not
|
|
[<em>enter your favourite here</em>]?</H3>
|
|
|
|
Well, the original name proposed for this SRFI was <code>curry</code>
|
|
which immediately stirred some emotions as it does not what is
|
|
commonly known as currying.
|
|
Some alternatives have been discussed, such as <code>section</code>,
|
|
<code>specialise</code>, <code>specialize</code>, <code>partial-apply</code>,
|
|
<code>partial-call</code>, <code>partial-lambda</code>,
|
|
<code>_j</code>, <code>_i</code>, <code>$</code>,
|
|
<code>&</code>, <code>srfi-26</code>, <code>foobar</code>,
|
|
<code>xyz</code>, <code>schoenfinkelize</code>,
|
|
<code>curry-which-isnt-curry</code>, <code>tandoori</code>,
|
|
and it has also been suggested to pick a five letter symbol uniformly
|
|
at random and fix this as a name.
|
|
To be fair, not all of these name have been put forward as serious proposals,
|
|
some of them were merely to illustrate a point in the discussion.
|
|
In addition, I have played with the game of the name quite a bit
|
|
and considered other candidates not listed here.
|
|
Despite the fact that the discussion list only represents a highly
|
|
biased random sample of people's opinion (motivation to post a message
|
|
is higher if you disagree, for example) it told me that the SRFI
|
|
could potentially benefit from a different name---however impractical
|
|
it may be to go for unanimous popularity.
|
|
The name <code>cut</code> refers to "operator section", as the
|
|
concept is often called in other programming languages,
|
|
but I tend to remember it as the acronym for "Curry Upon This" ;-).
|
|
The names for the evaluating version of <code>cut</code> that
|
|
have been proposed were <code>cut!</code>, <code>cutlet</code>,
|
|
<code>cut*</code>, and <code>cute</code>.<p>
|
|
|
|
<H3>Is it possible to implement the SRFI without macros?</H3>
|
|
|
|
Not really.
|
|
As Stephan Houben has pointed out during the discussion (refer to
|
|
<a href="http://srfi.schemers.org/srfi-26/mail-archive/msg00008.html">"Implementing it as a procedure"</a>) it is possible to implement the
|
|
<code>cute</code>-mechanism as a procedure.
|
|
Refer also to Al Petrofsky's posting
|
|
<a href="http://srfi.schemers.org/srfi-26/mail-archive/msg00048.html">"Problems with "curry"'s formal specification"</a> for details.
|
|
However, the procedural implementation comes with a slight performance
|
|
penalty and it is not possible the implement the <code>cut</code>-mechanism
|
|
as a procedure, too.
|
|
As both are needed, we rely on macros to implement the SRFI.
|
|
|
|
<H3>Why is there another symbol for the rest-slot when lambda-expressions
|
|
use the dotted notation for variable length argument lists?</H3>
|
|
There are two reasons.
|
|
The first one is the existence of a procedural implementation
|
|
of a related mechanism (refer to the previous paragraph).
|
|
For a procedure, however, it is not possible to have dotted notation.
|
|
The second reason is the way the hygienic macro mechanism in R5RS
|
|
is defined to deal with dotted notation, as Felix Winkelmann has pointed out.
|
|
Refer to the discussion threads
|
|
<a href="http://srfi.schemers.org/srfi-26/mail-archive/msg00001.html">"Improper lists in macros [WAS: none]"</a>.<p>
|
|
|
|
<H3>Why is it impossible to specify when a non-slot is evaluated individually
|
|
per non-slot?</H3>
|
|
<code>Cut</code> evaluates all non-slots at the time the specialized
|
|
procedure is called and <code>cute</code> evaluates all non-slots at
|
|
the time the procedure is being specialized.
|
|
These are only the two extremes and it is possible to define a
|
|
syntax that allows to choose per non-slot.
|
|
However, I am convinced that the benefit of the greater flexibility
|
|
is not worth the risk of confusion.
|
|
If a piece of code really depends on the distinction, it might be
|
|
better to make this explicit through <code>let</code> and
|
|
<code>lambda</code>.<p>
|
|
|
|
<H3>Why is <code>(cut if <> 0 1)</code> etc. illegal?</H3>
|
|
|
|
It is specified that a <code><slot-or-expr></code> must be
|
|
either the slot symbol or an <code><expression></code> in the sense
|
|
of <a href="http://www.schemers.org/Documents/Standards/R5RS/HTML/r5rs-Z-H-10.html#%_sec_7.1.3"><I>R5RS,
|
|
Section 7.1.3</I></a>.
|
|
As <code>if</code> is no <code><expression></code>,
|
|
the above case is illegal.
|
|
The reason why <code>cut</code> and <code>cute</code> are
|
|
restricted in this sense is the difficulty of defining
|
|
the meaning of such generalized expressions.
|
|
Please refer to the discussion archive for details.
|
|
|
|
<H1>Acknowledgements</H1>
|
|
|
|
An important part of this SRFI is based on the contribution
|
|
of other people, mostly through the discussion archive.
|
|
In particular, the semantics and the design rationale have
|
|
been greatly improved in the course of the discussion.
|
|
I would like to thank all who have contributed.
|
|
|
|
<H1>Copyright</H1>
|
|
<p>Copyright (C) Sebastian Egner (2002). All Rights Reserved.</p>
|
|
|
|
<p>
|
|
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:
|
|
</p>
|
|
<p>
|
|
The above copyright notice and this permission notice shall be
|
|
included in all copies or substantial portions of the Software.
|
|
</p>
|
|
<p>
|
|
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.
|
|
</p>
|
|
|
|
<hr>
|
|
<address>Editor: <a href="mailto:srfi-editors@srfi.schemers.org">Mike Sperber</a></address>
|
|
<address>Author: <a href="mailto:sebastian.egner@philips.com">Sebastian Egner</a></address>
|
|
<!-- Created: Mon Feb 4 15:20:00 EST 2002 -->
|
|
<!-- hhmts start -->
|
|
Last modified: Wed Jun 19 10:54:36 MST 2002
|
|
<!-- hhmts end -->
|
|
</body>
|
|
</html>
|