Let me introduce a funny idea.
If the outer-most parenthesis of the let-formal is taken off, We can use
the
lambda-formal without additional key-words and parenthesis complexity.
However, it is swindling by a clever trick, because the taken-off
parenthesis
should be inserted later. Of course, it becomes incompatible with
r5rs-let*.
Rough spec: (bare-let* (a1 a2 ...) ... () body1 body2 ...)
(bare-let* ((a 10) (b 20))
((c d e) (values 30 40 50))
((f . g) (apply values '(60 70 80 90)))
(h 100)
() ; a parenthesis taken off
(list a b c d e f g h))
=> (10 20 30 40 50 60 (70 80 90) (100))
(define-syntax bare-let*
(syntax-rules ()
((bare-let* () clause ...)
((lambda () clause ...)))
((bare-let* ((name val) ...) clause ...)
(let* ((name val) ...)
(bare-let* clause ...)))
((bare-let* (formal vals) clause ...)
(call-with-values (lambda () vals)
(lambda formal
(bare-let* clause ...))))))
It can be extended as followings.
(bare-let* (_ (a 10) (b 20)) ; let
(* (c 30) (d 40)) ; let*
(% (e (lambda () 1))) ; letrec
(& (f 50) (g 60)) ; and-let
(&* (h 70) (i 80) (j 90)) ; and-let*
(lp (k 100) (l 200)) ; named let
(loop (m n . o) (apply values '(300 400))) ; named let
(() (display (list k l m n o)) (newline)) ; begin
(~ '(500 600) (p 1 (number? p)) (q 2)) ; let-optional
(~* '(700 800 900) (r 3) (s 4) t) ;let-optional*
()
(display "examxple:")
(if (< m 500)
(loop 555 666 777 888)
(list a b c d e f g h i j k l m n o p q r s t)))
=>
(100 200 300 400 ())
examxple:(100 200 555 666 (777 888))
examxple:(10 20 30 40 #<procedure:e> 50 60 70 80 90 100 200 555 666 (777
888) 500 600 700 800 (900))
(define-syntax bare-let*
(syntax-rules (~ ~* ! !* % & &* * _) ; @ # $ ^ + |
((bare-let* () clause ...)
((lambda () clause ...)))
((bare-let* ((name val) ...) clause ...)
((lambda (name ...)
(bare-let* clause ...))
val ...))
((bare-let* (_ (name val) ...) clause ...)
(let ((name val) ...)
(bare-let* clause ...)))
((bare-let* (* (name val) ...) clause ...)
(let* ((name val) ...)
(bare-let* clause ...)))
((bare-let* (% (name val) ...) clause ...)
(letrec ((name val) ...)
(bare-let* clause ...)))
((bare-let* (& (name val) ...) clause ...)
(and-let ((name val) ...)
(bare-let* clause ...)))
((bare-let* (&* (name val) ...) clause ...)
(and-let* ((name val) ...)
(bare-let* clause ...)))
;; The order of followings are important.
((bare-let* (~ rest p1 p2 ...) clause ...)
(let-opt rest (p1 p2 ...)
(bare-let* clause ...)))
((bare-let* (~* rest p1 p2 ...) clause ...)
(let-opt* rest (p1 p2 ...)
(bare-let* clause ...)))
((bare-let* (! rest p1 p2 ...) clause ...)
(let-cat rest (p1 p2 ...)
(bare-let* clause ...)))
((bare-let* (!* rest p1 p2 ...) clause ...)
(let-cat* rest (p1 p2 ...)
(bare-let* clause ...)))
((bare-let* (() expression ...) clause ...)
((lambda ()
expression ... (bare-let* clause ...))))
((bare-let* (loop (name val) ...) clause ...)
((letrec ((loop (lambda (name ...)
(bare-let* clause ...))))
loop)
val ...))
((bare-let* (loop formal vals) clause ...)
(letrec ((loop (lambda formal
(bare-let* clause ...))))
(call-with-values (lambda () vals)
loop)))
((bare-let* (formal vals) clause ...)
(call-with-values (lambda () vals)
(lambda formal
(bare-let* clause ...))))))
(define-syntax and-let
(syntax-rules ()
((and-let ((name val) ...) body1 body2 ...)
(and val ...
((lambda (name ...) body1 body2 ...)
val ...)))
;; ((and-let tag ((name val) ...) body1 body2 ...)
;; (and val ...
;; ((letrec ((tag (lambda (name ...) body1 body2 ...)))
;; tag)
;; val ...)))
))
(define-syntax and-let*
(syntax-rules ()
((and-let* () body1 body2 ...)
((lambda () body1 body2 ...)))
((and-let* ((name1 val1) (name2 val2) ...) body1 body2 ...)
;;(and-let ((name1 val1))
;; (and-let* ((name2 val2) ...) body1 body2 ...)))))
(and val1
((lambda (name1) (and-let* ((name2 val2) ...) body1 body2
...))
val1)))))
--
Joo ChurlSoo