This SRFI is currently in withdrawn status. Here is an explanation of each status that a SRFI can hold. To provide input on this SRFI, please send email to srfi-182@nospamsrfi.schemers.org
. To subscribe to the list, follow these instructions. You can access previous messages via the mailing list archive.
Unlike the VALUES and CALL-WITH-VALUES mechanism of R5RS, this SRFI uses an explicit representation for multiple return values as a single value, namely a procedure. Decomposition of multiple values is done by simple application. The macro, ADBMAL, evaluates to a procedure that takes one procedure argument. The ADBMAL macro can be compared with LAMBDA. While a LAMBDA expression that consists of <formals> and <body> requires some actual arguments later when the evaluated LAMBDA expression is called, an ADBMAL expression that consists of <expression>s corresponding to actual arguments of LAMBDA requires <formals> and <body>, that is, an evaluated LAMBDA expression, later when the evaluated ADBMAL expression is called.
This SRFI also introduces the new LET-syntax ALET and ALET*, which depend on ADBMAL to manipulate multiple values, and which are compatible with LET and LET* of R5RS in single-value bindings. They also have a binding form making use of VALUES and CALL-WITH-VALUES to handle multiple values, and new binding forms for list, cons, and other multiple values. In addition, they have several new binding forms for useful functions such as escape, iteration, optional arguments, etc.
This SRFI is based on SRFI 86. The ALET and ALET* macros of this revised one are extended and changed in following aspects compared with those of the old one:
(() expression1 expression2 ...)
, is removed.It is impossible to bind the evaluated result of VALUES expression to a single variable unlike other Scheme expressions. Moreover, the pair of VALUES and CALL-WITH-VALUES was clumsy to use and somewhat slow under some circumstances. A solution would be to enclose the arguments of a VALUES expression in a procedure of one argument, a consumer procedure of CALL-WITH-VALUES. The following are examples to show the differences.
(define ls (list 20 30)) => (list 20 30) (define v (values 10 20 30)) => error or 10 or 10 20 30 (define v (lambda () (values 10 20 30))) => (lambda () (values 10 20 30)) (define m (adbmal 10 20 30)) => (lambda (f) (f 10 20 30)) (define m (adbmal* 10 20 30)) => (lambda (f) (f 10 20 30)) (define a (apply values 10 ls)) => error or 10 or 10 20 30 (define a (lambda () (apply values 10 ls))) => (lambda () (apply values 10 ls)) (define n (adbmals 10 ls)) => (lambda (f) (apply f 10 ls)) (define n (apply adbmal* 10 ls)) => (lambda (f) (apply f 10 ls)) (call-with-values v list) => (10 20 30) (m list) => (10 20 30) (call-with-values a list) => (10 20 30) (n list) => (10 20 30)The ALET and ALET* macros are examples of the use of ADBMAL. The differences between this LET-syntax and others, and some additional functions, are best explained by simple examples. In fact, the main purpose for this SRFI is to rearrange or rebuild the ALET and ALET* macros of SRFI 86.
The expressions for ALET bindings are evaluated in sequence from left to right, unlike LET of R5RS, R6RS, and SRFI 71.
In SRFI 71:
(let ((a (begin (display "1st") 1)) (b c (values (begin (display "2nd") 2) 3)) (d (begin (display "3rd") 4)) ((values e . f) (values (begin (display "4th") 5) 6))) (list a b c d e f)) => 2nd4th1st3rd(1 2 3 4 5 (6))
In this SRFI:
(alet ((a (begin (display "1st") 1)) (values b c (values (begin (display "2nd") 2) 3)) (d (begin (display "3rd") 4)) ((values e . f) (values (begin (display "4th") 5) 6))) (list a b c d e f)) => 1st2nd3rd4th(1 2 3 4 5 (6))
They have a binding form that uses CALL-WITH-VALUES and VALUES to handle multiple values with a syntactic keyword `values' as in SRFI 71.
(define mal (adbmal 1 2)) (define val (lambda () (values 1 2))) (alet* ((adbmal a b mal) (values c d (val)) ;different from SRFI 71 ((adbmal e . f) mal) ((values g . h) (val)) ((adbmal . i) mal) ((values . j) (val))) (list a b c d e f g h i j)) => '(1 2 1 2 1 (2) 1 (2) (1 2) (1 2))
They have binding forms that use LIST and CONS to handle multiple values. The bindings that require multiple values can take multiple expressions, if syntactically possible, as well as a single expression that produces multiple values.
(define ls (list 3 4 5)) (alet* ((cons a b ls) ((cons c d) ls) (e f g ls) ((h i j) ls) ((k . l) ls) ((m n o) 3 4 5) ((p . q) 3 4 5) ((r) ls) (s ls)) (list a b c d e f g h i j k l m n o p q r s)) => '(3 (4 5) 3 (4 5) 3 4 5 3 4 5 3 (4 5) 3 4 5 3 (4 5) (3 4 5) (3 4 5))
The named-ALET and named-ALET* are allowed to take multiple- valued bindings. They have a new binding form that has an iterative function like named-ALET.
In SRFI 71:
(let tag ((a 1) (b 2) (c 3) (d 4) (e 5)) (if (< a 10) (tag 10 b c d e) (list a b c d e))) => '(10 2 3 4 5)
In this SRFI:
(define cs (cons 1 2)) (define ls (list 3 4 5)) (define mal (adbmal 1 2)) (define val (lambda () (values 1 2))) (alet tag ((cons a b cs) (c d e ls)) (if (< a 10) (tag 10 b c d e) (list a b c d e))) => '(10 2 3 4 5) (alet (((cons a b cs) (c d e ls) . tag)) (if (< a 10) (tag 10 b c d e) (list a b c d e))) => '(10 2 3 4 5) (alet* tag ((cons a b cs) (c d e ls) ((adbmal c . d) mal) (e a)) (if (< a 10) (tag 10 b c d e c d 10) (list a b c d e))) => '(10 2 1 (2) 10) (alet* (((cons a b cs) (c d e ls) ((adbmal c . d) mal) (e a) . tag)) (if (< a 10) (tag 10 b c d e c d 10) (list a b c d e))) => error lambda: duplicate argument name at: c (alet* ((values a b (val)) ((cons a b cs) (c d e ls) . tag)) (if (< a 10) (tag 10 b c d e) (list a b c d e))) => '(10 2 3 4 5)
They have a new binding form that has an escape function.
(alet ((exit) (a (begin (display "1st") 1)) (adbmal b c (adbmal (begin (display "2nd") 2) (begin (display "3rd") 3)))) (display (list a b c)) (exit 10) (display "end")) => 1st2nd3rd(1 2 3)10
The AND-LET and AND-LET* are integrated into the ALET and ALET* with a syntactic keyword `and'.
(alet ((and (a (begin (display "1st") 1)) (b (begin (display "2nd") 2)) (c (begin (display "false") #f)) (d (begin (display "3nd") 3)))) (list a b c d)) => 1st2ndfalse#f (alet* ((and (a (begin (display "1st") 1)) (b (begin (display "2nd") 2)) (c (begin (display "false") #f) (< a b)) ;different from SRFI-2 (d (begin (display "3rd") 3) (< d a)))) ;different from SRFI-2 (list a b c d)) => 1st2ndfalse3rd#f
The LETREC and LETREC* forms are integrated into the ALET and ALET* with a syntactic keyword `rec'.
(alet* ((a 1) (rec (a 2) (b (lambda () c)) (c a)) (d 50)) (list a (b) c d)) => (2 2 2 50)
The REST-VALUES of SRFI 51, SRFI 54 and the LET-KEYWORDS are integrated into the ALET and ALET*.
8-1. optional sequent arguments ((lambda rest (alet* ((() rest num cha str)) (list num cha str))) 10) => (10 #f #f) ((lambda rest (alet* ((('undefined) rest num cha str)) (list num cha str))) 10) => (10 undefined undefined) ((lambda rest (alet* ((() rest (num 1) (cha #\a) (str "s") . rem)) (list num cha str rem))) 10) => (10 #\a "s" ()) 8-2. optional keyword arguments ((lambda rest (alet (((#t) rest ('num 1) 'cha 'str)) (list num cha str))) 'str "s" 'num 10) => (10 #t "s") ((lambda rest (alet ((() rest (('num num:) 1) (('cha cha:)) (('str str:)))) (list num cha str))) str: "s" num: 10) => (10 #f "s") 8-3. optional unnamed arguments ((lambda rest (alet ((() rest (,num 1 (number? num)) (,cha #\a (char? cha)) ,str)) (list num cha str))) #\c 10) => (10 #\c #f)
syntax: (adbmal expr ...) => (lambda (f) (f expr ...)) (adbmals expr ...) => (lambda (f) (apply f expr ...)) procedure: (adbmal* . exprs) => (lambda (f) (apply f exprs))
The ADBMAL evaluates to a procedure of one argument. The environment in effect when the macro expression was evaluated is remembered as part of the procedure. When the procedure is later called with an actual argument, a procedure, the environment in which the macro was evaluated is extended by binding <expr>s to the corresponding variables in the formal argument list of the argument procedure. The argument procedure of ADBMAL is called with the <expr>s. The ADBMAL* is a procedural equivalent of ADBMAL and ADBMALS.
(alet (<binding spec> ...) body) (alet* (<binding spec> ...) body)
The ALET* is to the ALET what the LET* is to the LET. However, the <binding spec>s of ALET are evaluated in sequence from left to right unlike LET of R5RS. The ALET and ALET* make use of ADBMAL as well as VALUES to handle multiple values. So, the single <expr> of multiple values binding should be a ADBMAL expression, or its equivalent. And the number of arguments of ADBMAL must match the number of values expected by the binding specification. Otherwise an error is signaled, as LAMBDA expression would.
syntax-rules identifier: adbmal values cons rec and quote quasiquote unquote
The variables of each <binding spec> are bound as follows:
1. (<var> <expr>) ((lambda (<var>) body) <expr>)
2-1. (<var1> <var2> <var3> ... <list expression>) (apply (lambda (<var1> <var2> <var3> ...) body) <list expression>)
2-2. (adbmal <var1> <var2> ... <adbmal expression>) (<adbmal expression> (lambda (<var1> <var2> ...) body))
2-3. (values <var1> <var2> ... <values expression>) (call-with-values (lambda () <values expression>) (lambda (<var1> <var2> ...) body)
2-4. (cons <var1> <var2> <pair expression>) ((lambda (<var1> <var2>) body) <pair expression>)
3-1. ((<var1> <var2> <var3> ...) <list expression>) is the same as 2-1.
3-2. ((adbmal <var1> <var2> ...) <adbmal expression>) is the same as 2-2.
3-3. ((values <var1> <var2> ...) <values expression>) is the same as 2-3.
3-4. ((cons <var1> <var2>) <pair expression>) is the same as 2-4.
4-1. ((<var1> <var2> ... . <varn>) <list expression>) (apply (lambda (<var1> <var2> ... . <varn>) body) <list expression>)
4-2. ((adbmal <var1> ... . <varn>) <adbmal expression>) (<adbmal expression> (lambda (<var1> ... . <varn) body))
4-3. ((values <var1> ... . <varn>) <values expression>) (call-with-values (lambda () <values expression>) (lambda (<var1> ... . <varn) body))
5-1. ((<var1> <var2> ...) <expr1> <expr2> ...) ((lambda (<var1> <var2> ...) body) <expr1> <expr2> ...)
5-2. ((<var1> <var2> ... . <varn>) <expr1> <expr2> <expr3> ...) ((lambda (<var1> <var2> ... . <varn>) body) <expr1> <expr2> <expr3> ...)
6. (<binding spec> ... . <var>) ;iterative function <var> ;iterative thunk ((letrec ((var (lambda (<variables of binding spec> ...) body))) var) <expressions of binding spec> ...)
7. (<var>) ;escape function (call-with-current-continuation (lambda (<var>) body))
8. (rec (<var1> <expr1>) (<var2> <expr2>) ...) (letrec[*] ((<var1> <expr1>) (<var2> <expr2>) ...) body)
9. (and (<var1> <expr1> [<test1>]) (<var2> <expr2> [<test2>]) ...)
Each <expr> is evaluated sequentially and bound to the corresponding <var>. During the process, if there is no <test> and the value of <expr> is false, it stops and returns #f. When there is a <test>, the process is continued regardless of the value of <expr> unless the value of <test> is false. If the value of <test> is false, it stops and returns #f.
10. (<optional delimeter> <rest list> <cl1> <cl2> ... . <rest var>) <optional delimeter> --> () | (default) <cl> --> <vars> | (<vars> <default> [<test>] [<true substitute>] [<false substitute>]) | (<vark> [<default>] [<test>] [<true substitute>] [<false substitute>]) <vars> --> <var> ;<optional sequent variable> | '<var> ;<optional keyword variable>: two in a time | `<var> ;<optional keyword variable>: one in a time | ,<var> ;<optional unnamed variable> <vark> --> ('<var> <keyword> [<equivalence predicate>]) |(`<var> <keyword> [<equivalence predicate>]) <equivalence predicate> --> eq? ;default equivalent predicate | eqv? | equal?
There are two types of optional delimiter. One is an empty list and the other is a list with one element. The former has #f as the default value and the latter has its element.
The <optional sequent variable> is bound to the first one of the remaining elements of <rest list>. If there are no more elements, it is bound to the <default>.
The <optional unnamed variable> is temporarily bound to each of remaining elements of <rest list> sequentially until <test> returns a true value, at which point it is finally bound to the passed element. If there is no <test>, the first one of the remaining elements of <rest list> is regarded as passing. If any element does not pass the <test>, it is bound to the <default>. If there is a <false substitute> and <test> returns a false value, it is finally bound to the <false substitute> instead of the above process. If there is a <true substitute> and <test> returns a true value, it is finally bound to the <true substitute>.
The keyword used for the corresponding <optional keyword variable> is a symbol of the same name as the <var> or <keyword>. The remaining elements are interpreted one by one (quote symbol) or two in a time (quasiquote symbol) until an element is the keyword, at which point the variable is bound to the next element. If there is no keyword or the keyword is the last element, the variable is bound to the <default>.
The following rules are applied to <optional sequent variable> and <optional keyword variable>: If there is a <test>, it is evaluated only when <var> is bound to an element of <rest list>. If it returns a false value and there is no <false substitute>, an error is signaled. If it returns a false value and there is a <false substitute>, <var> is rebound to the <false substitute> instead of signaling an error. If it returns a true value and there is a <true substitute>, <var> is rebound to the <true substitute>. When there are more elements than ones that are specified by <var>s, an error is signaled. But if <rest var> is given, it is bound to the remaining elements.
(alet name (<binding spec> ...) body) (alet* name (<binding spec> ...) body)
These are the same as the named LET except binding specification. These allow all sorts of bindings in <binding spec>.
Sample implementations are provided based on both
define-syntax
and define-macro
. They're
available both in the Github repo and in this .tgz
file.
[R5RS] | Richard Kelsey, William Clinger, and Jonathan Rees: Revised(5) Report on the Algorithmic Language Scheme.http://www.schemers.org/Documents/Standards/R5RS/ |
[R6RS] | Michael Sperber, R. Kent Dybvig, Matthew Flatt, and Anton von Straaten: Revised(6) Report on the Algorithmic Language Scheme.http://www.r6rs.org |
[SRFI 2] | Oleg Kiselyov: AND-LET*: and AND with local bindings, a guarded LET* special form.https://srfi.schemers.org/srfi-2/ |
[SRFI 11] | Lars T. Hansen: Syntax for receiving multiple values.https://srfi.schemers.org/srfi-11/ |
[SRFI 51] | Joo ChurlSoo: Handling rest list.https://srfi.schemers.org/srfi-51/ |
[SRFI 54] | Joo ChurlSoo: Formatting.https://srfi.schemers.org/srfi-54/ |
[SRFI 71] | Sebastian Egner: Extended LET-syntax for multiple values.https://srfi.schemers.org/srfi-71/ |
[SRFI 86] | Joo ChurlSoo: MU and NU simulating VALUES & CALL-WITH-VALUES, and their related LET-syntax.https://srfi.schemers.org/srfi-86/ |
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 (including the next paragraph) 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.