1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190
|
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<html>
<head>
<title>SRFI 61: A more general COND clause</title>
</head>
<body>
<H1>Title</H1>
<p>A more general <code>cond</code> clause</p>
<H1>Author</H1>
<p>Taylor Campbell</p>
<H1>Status</H1>
<p>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 previous messages via
<a href="http://srfi.schemers.org/srfi-61/mail-archive/maillist.html">the archive of the mailing list</a>.</p>
<ul> <li>Received: <a href="http://srfi.schemers.org/cgi-bin/viewcvs.cgi/*checkout*/srfi/srfi-61/srfi-61.txt?rev=1.1">2005/01/04</a></li>
<li>Draft: 2005/01/03-2005/03/04</li>
<li>Final: 2005/07/21</li>
</ul>
<H1>Abstract</H1>
<p>This SRFI proposes an extension to the <code>cond</code> syntax to allow a more
general clause, one that allows binding the results of tests as in the
<code>=></code> clauses and user-defined meaning of the success & failure of tests.</p>
<H1>Rationale</H1>
<p>The present set of <code>cond</code> clauses is based on simple boolean testing. It
is prohibitively inexpressive in that the condition part of a <code>cond</code>
clause that uses <code>=></code> may pass only a single value to the receiver, and
it enforces a semantics whereby <code>#f</code> implies failure of the condition.
Programmers frequently use different tokens to imply failure, such as
in R5RS's I/O readers which return a distinguished 'EOF object' to
denote failure, and a successful condition may produce more than one
useful value. This simple extension allows any meaning of 'failure' to
be assigned on a per-clause basis, and it also allows the condition to
return multiple values to be passed to the receiver.</p>
<H1>Specification</H1>
<p>The <code><cond clause></code> production in the formal syntax of Scheme as written
by R5RS in section 7.1.3 is extended with a new option:</p>
<blockquote>
<pre><code> <cond clause> --->
...
| (<generator> <guard> => <receiver>)</code></pre>
</blockquote>
<p>where <code><generator></code>, <code><guard></code>, & <code><receiver></code> are all <code><expression></code>s.</p>
<p>Clauses of this form have the following semantics: <code><generator></code> is
evaluated. It may return arbitrarily many values. <code><Guard></code> is applied
to an argument list containing the values in order that <code><generator></code>
returned. If <code><guard></code> returns a true value for that argument list,
<code><receiver></code> is applied with an equivalent argument list. If <code><guard></code>
returns a false value, however, the clause is abandoned and the next
one is tried.</p>
<H1>Examples</H1>
<p>This <code>port->char-list</code> procedure accepts an input port and returns a list
of all the characters it produces until the end.</p>
<blockquote>
<pre><code> (define (port->char-list port)
(cond ((read-char port) char?
=> (lambda (c) (cons c (port->char-list port))))
(else '())))</code></pre>
</blockquote>
<p>Consider now a hypothetical <code>table-entry</code> procedure that accepts two
arguments, a table (perhaps a hash table) and a key to an entry that
may be in the table; it returns two values: a boolean that denotes
whether or not an entry with the given key was in the table and, if it
was, the value associated with the key. Also, a hypothetical <code>proj0</code>
combinator (projection of argument 0) returns its 0<sup>th</sup> argument and
ignores all others. One might conditionally branch to a certain body
of code if the table contains the desired entry like so with the new
type of <code>cond</code> clause:</p>
<blockquote>
<pre><code> (cond ...
((table-entry <table> <key>) proj0
=> (lambda (present? value)
...[VALUE is bound to the value of the entry]...))
...)</code></pre>
</blockquote>
<H1>Implementation</H1>
<p>The entirety of a syntax transformer for the new <code>cond</code> syntax is given
here. It uses an auxiliary macro, <code>cond/maybe-more</code>, to simplify the
construction of <code>if</code> expressions with or without more <code>cond</code> clauses. The
code is in the public domain.</p>
<blockquote>
<pre><code>(define-syntax cond
(syntax-rules (=> ELSE)
((COND (ELSE else1 else2 ...))
;; The (IF #T (BEGIN ...)) wrapper ensures that there may be no
;; internal definitions in the body of the clause. R5RS mandates
;; this in text (by referring to each subform of the clauses as
;; <expression>) but not in its reference implementation of COND,
;; which just expands to (BEGIN ...) with no (IF #T ...) wrapper.
(IF #T (BEGIN else1 else2 ...)))
((COND (test => receiver) more-clause ...)
(LET ((T test))
(COND/MAYBE-MORE T
(receiver T)
more-clause ...)))
((COND (generator guard => receiver) more-clause ...)
(CALL-WITH-VALUES (LAMBDA () generator)
(LAMBDA T
(COND/MAYBE-MORE (APPLY guard T)
(APPLY receiver T)
more-clause ...))))
((COND (test) more-clause ...)
(LET ((T test))
(COND/MAYBE-MORE T T more-clause ...)))
((COND (test body1 body2 ...) more-clause ...)
(COND/MAYBE-MORE test
(BEGIN body1 body2 ...)
more-clause ...))))
(define-syntax cond/maybe-more
(syntax-rules ()
((COND/MAYBE-MORE test consequent)
(IF test
consequent))
((COND/MAYBE-MORE test consequent clause ...)
(IF test
consequent
(COND clause ...)))))</code></pre>
</blockquote>
<H1>Copyright</H1>
<p>Copyright (C) 2004 Taylor Campbell. 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>
</body>
</html>
|