taking off parentheses of only a resting argument soo 07 Jul 2005 07:07 UTC

The previous one seems to be deviated from the focus of this srfi.

Now I suggest taking off the parentheses of only a resting argument.  Then the
following bare-let* becomes compatible with r5rs-let* and almost compatible
with let*-values, and any keyword such as values becomes needless.

Examples:

(bare-let* ((a 10)
	    (b c (values 20 30))
	    ((d e . f) (values 1 2 3 4))
	    g 111			; taking off a pair of parentheses
	    ((h) 40)			; This can be omitted.
	    ((i j) (values 50 60)))	; This can be omitted.
	   (list a b c d e f g h i j))

(srfi-let* ((a 10)
	    (b c (values 20 30))
	    ((values d e . f) (values 1 2 3 4))
	    ((values . g) 111)
	    ((values h) 40)
	    ((values i j) (values 50 60)))
	   (list a b c d e f g h i j))

(let*-values (((a) 10)
	      ((b c) (values 20 30))
	      ((d e . f) (values 1 2 3 4))
	      (g 111)			; incompatible with bare-let*
	      ((h) 40)
	      ((i j) (values 50 60)))
  (list a b c d e f g h i j))

=> '(10 20 30 1 2 (3 4) (111) 40 50 60)

(define-syntax bare-let*
  (syntax-rules ()
    ((bare-let* () body1 body2 ...)
     ((lambda () body1 body2 ...)))

    ;; extension --- intervening body
    ((bare-let* ((() a ...) clause ...) body1 body2 ...)
     ((lambda ()
	a ...
	(bare-let* (clause ...) body1 body2 ...))))

;;     ;; If commenting out, it becomes incompatible with let*-values
;;     ((bare-let* (((a b ...) c) clause ...) body1 body2 ...)
;;      (error "bare-let*: syntax error" '((a b ...) c)))

    ((bare-let* (((a . b) c) clause ...) body1 body2 ...)
     (call-with-values (lambda () c)
       (lambda (a . b)
	 (bare-let* (clause ...) body1 body2 ...))))

    ((bare-let* ((a1 a2 a3 ...) clause ...) body1 body2 ...)
     (many-let ((a1) (a2 a3 ...))
		(bare-let* (clause ...) body1 body2 ...)))

    ;; extension --- I like direct escape.
    ((bare-let* ((a) clause ...) body1 body2 ...)
     (call-with-current-continuation
      (lambda (a)
	(bare-let* (clause ...) body1 body2 ...))))

    ;; extension --- extended named-let*
    ((bare-let* ((a . b) clause ...) body1 body2 ...)
     (dot-let ((a) b)
	      (bare-let* (clause ...) body1 body2 ...)))

;;     ((bare-let* ((a . b) clause ...) body1 body2 ...)
;;      (error "bare-let*: syntax error" '(a . b)))

    ((bare-let* (a b clause ...) body1 body2 ...)
     (call-with-values (lambda () b)
       (lambda a
	 (bare-let* (clause ...) body1 body2 ...))))))

(define-syntax many-let
  (syntax-rules ()
    ((many-let ((a ...) (a1 a2 a3 ...)) body1 body2 ...)
     (many-let ((a ... a1) (a2 a3 ...)) body1 body2 ...))
    ((many-let ((a a1 ...) (b)) body1 body2 ...)
     (call-with-values (lambda () b)
       (lambda (a a1 ...) body1 body2 ...)))))

(define-syntax dot-let
  (syntax-rules ()
    ((dot-let ((a ...) (an . bn)) body1 body2 ...)
     (dot-let ((a ... an) bn) body1 body2 ...))
    ((dot-let ((a a1 ...)  b) body1 body2 ...)
     (%dot-let (() (a a1 ...) b) body1 body2 ...))))

(define-syntax %dot-let
  (syntax-rules ()
    ((%dot-let (((n v) ...) ((n1 v1) a2 ...) b) body1 body2 ...)
     (%dot-let (((n v) ... (n1 v1)) (a2 ...) b) body1 body2 ...))
    ((%dot-let (((n v) ...) (a1 a2 ...) b) body1 body2 ...)
     (%dot-let (((n v) ... (a1 a1)) (a2 ...) b) body1 body2 ...))
    ((%dot-let (((n v) ...) () b) body1 body2 ...)
     ((letrec ((b (lambda (n ...) body1 body2 ...)))
       b)
      v ...))))

;; extended example
(bare-let* ((a 10)
	    (b c (values 20 30))
	    d 1000
	    (h)
	    ((k 11) a (l 22) . m)
	    (() (display "test") (newline))
	    ((e f . g) (apply values '(1 2 3 4 5))))
	   (if (< a 20)
	       (begin (display (list a b c k l)) (newline) (m 100 200 300))
	       (display (list a b c k l d e f g h)))
	   (newline)
	   (display "this is a test")
	   (newline)
	   (h)
	   (display "this is not seen")
	   (newline))
=>
test
(10 20 30 11 22)
test
(200 20 30 100 300 (1000) 1 2 (3 4 5) #<continuation>)
this is a test
--
Joo ChurlSoo