一个连续的 Do for scheme (do*)
A sequential Do for scheme (do*)
在Common Lisp中,有一种顺序形式(do *vars* *test* *body*)
;就像 let 的顺序并行 let*
,它一次通过 *vars*
工作,这样你就可以像这样回顾以前定义的变量:
(do* ((a '(1 2 3) (cdr a))
(b (mapcar (lambda (x) (1+ x)) a) (cdr b)))
((= 1 1) (list 'a a 'b b)))
; (a (1 2 3) b (2 3 4))
在 Scheme 中,AFAIK,没有相关的函数或宏。有 do
,但没有 do*
。我一直在尝试为 Chicken Scheme 编写 do*
的实现,但到目前为止,我一直在努力取得任何进展……我想,我真的说不准。我熟悉 Chicken Scheme,但我总是觉得 scheme 宏令人困惑。
这是我目前得到的:
(##sys#extend-macro-environment
'do*
'()
(##sys#er-transformer
(lambda (form r c)
(##sys#check-syntax 'do* form '(_ #((symbol _ . #(_)) 0) . #(_ 1)))
(let* ((bindings (cadr form))
(test (caddr form))
(body (cdddr form))
(do*var (r 'doloop)))
`(let*
,do*var
,(##sys#map (lambda (b) (list (car b) (car (cdr b)))) bindings)
(##core#if ,(car test)
,(let ((tbody (cdr test)))
(if (eq? tbody '())
'(##core#undefined)
`(##core#begin ,@tbody) ) )
(##core#begin
,(if (eq? body '())
'(##core#undefined)
`(##core#let () ,@body) )
(##core#app
,do*var ,@(##sys#map (lambda (b)
(if (eq? (cdr (cdr b)) '())
(car b)
(car (cdr (cdr b))) ) )
bindings) ) ) ) ) ) ) ) )
但我不断收到 doloop
not being a list 这样的错误——目前,我正在收到
Error: during expansion of (do* ...) - in `do*' - symbol expected: (do* ((a (quote (1 2 3)) (cdr a)) (b (map (lambda (x) (+ 1 x)) a) (cdr b)) ((= 1 1) (list (quote a) a (quote b) b))))
Call history:
<syntax> (do* ((a (quote (1 2 3)) (cdr a)) (b (map (lambda (x) (+ 1 x)) a) (cdr b)) ((= 1 1) (list (quote a) a...
<eval> (##sys#check-syntax (quote do*) form (quote (_ #((symbol _ . #(_)) 0) . #(_ 1)))) <--
这是摘自 HyerSpec:
的 Common Lisp 粗略 do*
(block nil
(let ((var1 init1)
(var2 init2)
...
(varn initn))
declarations
(loop (when end-test (return (progn . result)))
(tagbody . tagbody)
(psetq var1 step1
var2 step2
...
varn stepn))))
do* is similar, except that let* and setq replace the let and psetq, respectively.
下面是 do*
在 CL 中的扩展:
(expand-form '(do* ((a '(1 2 3) (cdr a))
(b (mapcar (lambda (x) (1+ x)) a) (cdr b)))
((= 1 1) (list 'a a 'b b))))
(block nil
(let* ((a '(1 2 3)) (b (mapcar #'(lambda (x) (declare (system::source ((x) (1+ x)))) (1+ x)) a)))
(tagbody #:loop-5382 (if (= 1 1) (go #:end-5383)) (setq a (cdr a) b (cdr b)) (go #:loop-5382) #:end-5383 (return-from nil (list 'a a 'b b))))) ;
;t
请不要使用## 前缀的标识符。这些不受支持,并且 不是 官方 API!
的一部分
其次,与其试图去搞低级宏,不如使用语法规则,它更简单、更不容易出错并且标准化。只要你不需要破坏卫生,就应该使用它。
这里有一个 do* 的例子,如果我理解正确的话它会起作用:
(define-syntax do*
(syntax-rules ()
((_ ((?var0 ?init0 ?inc0) ...)
(?test ?result)
?body ...)
(let* ((?var0 ?init0) ...)
(let lp ()
(cond (?test ?result)
(else ?body ...
(set! ?var0 ?inc0) ...
(lp))))))))
表示为隐式重命名宏:
(define-syntax do*
(ir-macro-transformer
(lambda (e i c)
(let* ((vars (cadr e))
(test&result (caddr e))
(test (car test&result))
(result (cadr test&result))
(body-exprs (cdddr e)))
`(let* (,@(map (lambda (v) (list (car v) (cadr v))) vars))
(let lp ()
(cond (,test ,result)
(else ,@body-exprs
,@(map (lambda (v) `(set! ,(car v) ,(caddr v))) vars)
(lp)))))))))
我希望你同意这样更冗长。
在Common Lisp中,有一种顺序形式(do *vars* *test* *body*)
;就像 let 的顺序并行 let*
,它一次通过 *vars*
工作,这样你就可以像这样回顾以前定义的变量:
(do* ((a '(1 2 3) (cdr a))
(b (mapcar (lambda (x) (1+ x)) a) (cdr b)))
((= 1 1) (list 'a a 'b b)))
; (a (1 2 3) b (2 3 4))
在 Scheme 中,AFAIK,没有相关的函数或宏。有 do
,但没有 do*
。我一直在尝试为 Chicken Scheme 编写 do*
的实现,但到目前为止,我一直在努力取得任何进展……我想,我真的说不准。我熟悉 Chicken Scheme,但我总是觉得 scheme 宏令人困惑。
这是我目前得到的:
(##sys#extend-macro-environment
'do*
'()
(##sys#er-transformer
(lambda (form r c)
(##sys#check-syntax 'do* form '(_ #((symbol _ . #(_)) 0) . #(_ 1)))
(let* ((bindings (cadr form))
(test (caddr form))
(body (cdddr form))
(do*var (r 'doloop)))
`(let*
,do*var
,(##sys#map (lambda (b) (list (car b) (car (cdr b)))) bindings)
(##core#if ,(car test)
,(let ((tbody (cdr test)))
(if (eq? tbody '())
'(##core#undefined)
`(##core#begin ,@tbody) ) )
(##core#begin
,(if (eq? body '())
'(##core#undefined)
`(##core#let () ,@body) )
(##core#app
,do*var ,@(##sys#map (lambda (b)
(if (eq? (cdr (cdr b)) '())
(car b)
(car (cdr (cdr b))) ) )
bindings) ) ) ) ) ) ) ) )
但我不断收到 doloop
not being a list 这样的错误——目前,我正在收到
Error: during expansion of (do* ...) - in `do*' - symbol expected: (do* ((a (quote (1 2 3)) (cdr a)) (b (map (lambda (x) (+ 1 x)) a) (cdr b)) ((= 1 1) (list (quote a) a (quote b) b))))
Call history:
<syntax> (do* ((a (quote (1 2 3)) (cdr a)) (b (map (lambda (x) (+ 1 x)) a) (cdr b)) ((= 1 1) (list (quote a) a...
<eval> (##sys#check-syntax (quote do*) form (quote (_ #((symbol _ . #(_)) 0) . #(_ 1)))) <--
这是摘自 HyerSpec:
的 Common Lisp 粗略do*
(block nil (let ((var1 init1) (var2 init2) ... (varn initn)) declarations (loop (when end-test (return (progn . result))) (tagbody . tagbody) (psetq var1 step1 var2 step2 ... varn stepn))))
do* is similar, except that let* and setq replace the let and psetq, respectively.
下面是 do*
在 CL 中的扩展:
(expand-form '(do* ((a '(1 2 3) (cdr a))
(b (mapcar (lambda (x) (1+ x)) a) (cdr b)))
((= 1 1) (list 'a a 'b b))))
(block nil
(let* ((a '(1 2 3)) (b (mapcar #'(lambda (x) (declare (system::source ((x) (1+ x)))) (1+ x)) a)))
(tagbody #:loop-5382 (if (= 1 1) (go #:end-5383)) (setq a (cdr a) b (cdr b)) (go #:loop-5382) #:end-5383 (return-from nil (list 'a a 'b b))))) ;
;t
请不要使用## 前缀的标识符。这些不受支持,并且 不是 官方 API!
的一部分其次,与其试图去搞低级宏,不如使用语法规则,它更简单、更不容易出错并且标准化。只要你不需要破坏卫生,就应该使用它。
这里有一个 do* 的例子,如果我理解正确的话它会起作用:
(define-syntax do*
(syntax-rules ()
((_ ((?var0 ?init0 ?inc0) ...)
(?test ?result)
?body ...)
(let* ((?var0 ?init0) ...)
(let lp ()
(cond (?test ?result)
(else ?body ...
(set! ?var0 ?inc0) ...
(lp))))))))
表示为隐式重命名宏:
(define-syntax do*
(ir-macro-transformer
(lambda (e i c)
(let* ((vars (cadr e))
(test&result (caddr e))
(test (car test&result))
(result (cadr test&result))
(body-exprs (cdddr e)))
`(let* (,@(map (lambda (v) (list (car v) (cadr v))) vars))
(let lp ()
(cond (,test ,result)
(else ,@body-exprs
,@(map (lambda (v) `(set! ,(car v) ,(caddr v))) vars)
(lp)))))))))
我希望你同意这样更冗长。