0

Common Lisp には、(do *vars* *test* *body*);の逐次形式があります。letの 順次 parallel とlet*同じよう*vars*に、一度に 1 つずつ処理されるため、以前に定義した変数を次のように参照できます。

(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))

スキームでは、知る限り、相関する関数やマクロはありません。ありますがdo、ありませんdo*。私は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ます-現在、私は取得しています

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))))     <--

以下は、 HyerSpecdo*から取得した Common Lispのラフです。

  (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* は似ていますが、let* と setq がそれぞれ let と psetq を置き換えている点が異なります。

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
4

1 に答える 1

1

## で始まる識別子は使用しないでください。これらはサポートされておらず、公式 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)))))))))

その方がはるかに冗長であることに同意していただければ幸いです。

于 2015-08-12T14:18:43.517 に答える