Title MU and NU simulating VALUES & CALL-WITH-VALUES, and their related LET-syntax Author Joo ChurlSoo Abstract Unlike the VALUES/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. Each of the two macros, MU and NU, evaluates to a procedure that takes one procedure argument. The MU and NU can be compared with LAMBDA. While LAMBDA expression that consists of and requires some actual arguments later when the evaluated LAMBDA expression is called, MU and NU expressions that consist of s corresponding to actual arguments of LAMBDA require and , that is, an evaluated LAMBDA expression, later when the evaluated MU and NU expressions are called. This SRFI also introduces new LET-syntax depending on MU and NU to manipulate multiple values, ALET and ALET* that 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. In addition, they have several new binding forms for useful functions such as escape, recursion, etc. Rationale 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 is clumsy to use and somewhat slow under some circumstances. A solution would be to enclose the arguments of VALUES expression in a procedure of one argument, a consumer procedure of CALL-WITH-VALUS. The following are examples to show the differences. (define v (values 1 2 3)) => error (define v (lambda () (values 1 2 3))) => (lambda () (values 1 2 3)) (define m (mu 1 2 3)) => (lambda (f) (f 1 2 3)) (define a (apply values 1 '(2 3))) => error (define a (lambda () (apply values 1 '(2 3)))) => (lambda () (apply values 1 '(2 3))) (define n (nu 1 '(2 3))) => (lambda (f) (apply f 1 '(2 3))) (call-with-values v list) => (1 2 3) (m list) => (1 2 3) (call-with-values a list) => (1 2 3) (n list) => (1 2 3) The ALET and ALET* are cases in point to use MU and NU. The differences between this LET-syntax and others, and some additional functions are best explained by simple examples. 1. The following are rest argument forms of each SRFI. In SRFI-11: (let-values ((a (values 1 2)) ((b c) (values 3 4))) (list a b c)) => ((1 2) 3 4) In SRFI-71: (srfi-let (((values . a) (values 1 2)) ((values b c) (values 3 4))) (list a b c)) => ((1 2) 3 4) In this SRFI: (alet (a (mu 1 2) ((b c) (mu 3 4))) (list a b c)) => ((1 2) 3 4) 2. The expressions for ALET bindings are evaluated in sequence from left to right unlike LET of R5RS and LET of SRFI-71. In SRFI-71: (srfi-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)) (b c (mu (begin (display "2nd") 2) 3)) (d (begin (display "3rd") 4)) ((e . f) (mu (begin (display "4th") 5) 6))) (list a b c d e f)) => 1st2nd3rd4th(1 2 3 4 5 (6)) 3. The bindings that require multiple values can take multiple expressions, if syntactically possible, as well as a single expression that produce multiple values. (alet* (((a b) (mu 1 2)) ((c d e) a (+ a b c) (+ a b c d)) ((f . g) (mu 5 6 7)) ((h i j . k) e 9 10 h i j)) (list a b c d e f g h i j k)) => (1 2 1 4 8 5 (6 7) 8 9 10 (8 9 10)) 4. The named-ALET and named-ALET* are allowed to take multiple values bindings. In SRFI-71: (srfi-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: (alet* tag ((a 1) (a b b c (mu (+ a 2) 4 5 6)) ((d e e) b 5 (+ a b c))) (if (< a 10) (tag a 10 b c c d e d) (list a b c d e))) => (10 6 6 5 5) 5. They have a new binding form that has a recursive function like named-ALET. It is also allowed to take multiple values bindings. (alet* ((a 1) ((b 2) (b c c (mu 3 4 5)) ((d e d (mu a b c)) . intag) . tag) (f 6)) (if (< d 10) (intag d e 10) (if (< c 10) (tag b 11 c 12 a b d intag) (list a b c d e f)))) => (1 11 12 10 3 6) 6. They have a new binding form that has an escape function. (alet ((exit) (a (begin (display "1st") 1)) (b c (mu (begin (display "2nd") 2) (begin (display "3rd") 3)))) (display (list a b c)) (exit 10) (display "end")) => 1st2nd3rd(1 2 3)10 7. 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) (< b 2)) ; different from SRFI-2 (c (begin (display "false") #f)) (d (begin (display "3nd") 3)))) (list a b c d)) => 1st2nd#f 8. The REST-VALUES of SRFI-51 is integrated into the ALET and ALET* with syntactic keywords `opt' and `cat' in the similar way to LET-OPTIONALS in Scsh. ((lambda (str . rest) (alet* ((len (string-length str)) (opt rest (start 0 (integer? start) (if (< start 0) 0 (if (< len start) len start))) ;true (end len (integer? end) (if (< end start) start (if (< len end) len end)))));true (substring str start end))) "abcdefg" 1 20) => "bcdefg" ((lambda (str . rest) (alet* ((len (string-length str)) (min (apply min rest)) (cat rest (start 0 (= start min) (if (< start 0) 0 (if (< len start) len start))) ;true (end len (integer? end) (if (< end start) start (if (< len end) len end)))));true (substring str start end))) "abcdefg" 20 1) => "bcdefg" ((lambda (str . rest) (alet ((cat rest (start 0 (and (list? start) (= 2 (length start)) (eq? 'start (car start))) (cadr start)) ; true (end (string-length str) (and (list? end) (= 2 (length end)) (eq? 'end (car end))) (cadr end)))) ; true (substring str start end))) "abcdefg" '(end 6) '(start 1)) => "bcdef" 9. The LET-KEYWORDS and LET-KEYWORDS* are integrated into the ALET and ALET* with a syntactic keyword `key'. They use any scheme objects as keywords. (define rest-list '(a 10 cc 30 40 b 20)) (alet ((key rest-list (a 1) (b 2) ((c 'cc) 3) . d)) (list a b c d)) => (10 2 30 (40 b 20)) (alet ((key rest-list (a 1) (b 2) ((c 'cc) 3) #f . d)) (list a b c d)) => (10 2 30 (40 b 20)) (alet ((key rest-list (a 1) (b 2) ((c 'cc) 3) #t . d)) (list a b c d)) => (10 20 30 (40)) (define rest (list 'a 10 'd 40 "c" 30 50 'b 20)) (alet ((key rest (a 1) (b 2) ((c "c") 3) . d)) (list a b c d)) => (10 2 30 (d 40 50 b 20)) (alet ((key rest (a 1) (b 2) ((c "c") 3) #f . d)) (list a b c d)) => (10 2 3 (d 40 "c" 30 50 b 20)) (alet ((key rest (a 1) (b 2) ((c "c") 3) #t . d)) (list a b c d)) => (10 20 30 (d 40 50)) ((lambda (m . n) (alet* ((opt n (a 10) (b 20) (c 30) . d) (key d (x 100) (y 200) (a 300))) (list m a b c x y))) 0 1 2 3 'a 30 'y 20 'x 10) => (0 30 2 3 10 20) ((lambda (m . n) (alet* ((key n (x 100) (y 200) (a 300) . d) (opt d (a 10) (b 20) (c 30))) (list m a b c x y))) 0 'a 30 'y 20 'x 10 1 2 3) => (0 1 2 3 10 20) 10. The LETREC and LETREC* are integrated into the ALET and ALET* with a syntactic keyword `rec'. (alet* ((a 1) (rec (a 2) (b 3) (b (lambda () c)) (c a)) (d 50)) (list a (b) c d)) => '(2 2 2 50) 11. They have a binding form that use CALL-WITH-VALUES and VALUES to handle multiple values with a syntactic keyword `values' like SRFI-71 . (alet ((a b (mu 1 2)) (values c d (values 3 4)) ;This is different from SRFI-71. ((e f) (mu 5 6)) ((values g h) (values 7 8)) ((i j . k) (nu 9 '(10 11 12))) ((values l m . n) (apply values 13 '(14 15 16))) o (mu 17 18) ((values . p) (values 19 20))) (list a b c d e f g h i j k l m n o p)) => (1 2 3 4 5 6 7 8 9 10 (11 12) 13 14 (15 16) (17 18) (19 20)) 12. They have a new binding form that works as an intervening external environment in ALET and as an intervening internal environment in ALET*. (alet ((a 1) (() (define a 10) (define b 100)) (b a)) (list a b)) => (1 10) (alet* ((a 1) (() (define a 10) (define b 100)) (b a)) (list a b)) => (10 10) Specification (mu ...) => (lambda (f) (f ...)) (nu ... ) => (lambda (f) (apply f ... )) The should be a list. Each macro 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 s to the corresponding variables in the formal argument list of the argument procedure. The argument procedure of MU is called with the s, and that of NU is applied to APPLY procedure with the s. (alet ( ...) body ...) (alet* ( ...) body ...) syntax-rules identifier: opt cat key and rec values : 1. ( ) 2. ( ... ) 3. (() ) 4. (( ... ) ) 5. (( ... . ) ) 6. (( ... ) ...) 7. (( ... . ) ... ...) 8. 9. () 10. ( ... . ) 11. (() . ) 12. (and ( []) ( []) ...) 13. (opt ( [ [ []]]) ... ( [ [ []]]) . []) 14. (cat ( [ [ []]]) ... ( [ [ []]]) . []) 15. (key ( [ [ []]]) ... ( [ [ []]]) [