2016-11-11 5 views
1

私のコードで構造体を式に転送し、それを評価して元の構造体を取得します。ここに私のコードは次のとおりです。なぜ私のスキームマクロはうまくいきませんか?

(define-syntax expr-returning (syntax-rules() 
          ((expr-returning (car x)) '(car (expr-returning x))) 
          ((expr-returning (cdr x)) '(cdr (expr-returning x))) 
          ((expr-returning (cons x y)) '(cons (expr-returning x) (expr-returning y))) 
          ((expr-returning obj) (cond [(null? obj) 'null] 
                 [(number? obj) 'obj] 
                 [(char? obj) 'obj] 
                 [(boolean? obj) 'obj] 
                 [(pair? obj) (expr-returning (cons (car obj) (cdr obj)))] 
                 [else 'error] 
               )))) 
ここ

は私のテストで:

(define ls (append '(a e i o u) 'y)) 
(define d (cons ls (cdr (cdr ls)))) 
(define e (expr-returning d)) 

d 
e 
(eval e) 

出力は私の短所と間違って何

'((a e i o u . y) i o u . y) 
'(cons (expr-returning (car d1)) (expr-returning (cdr d1))) 
cons: unbound identifier; 
also, no #%app syntax transformer is bound in: cons 

のですか?

+1

私はDrRacketであなたの例を試してみましたが、それは動作します: '(evalのE)' => ''((カー(式expr-返すd))はCDR(式exprを返しますd)) '。 – Renzo

答えて

0

コードを見ると、コードが実行される前にマクロ展開が行われているので意味がありません。

(define-syntax expr-returning 
    (syntax-rules() 
    ((expr-returning (car x)) '(car (expr-returning x))) 
    ((expr-returning (cdr x)) '(cdr (expr-returning x))) 
    ((expr-returning (cons x y)) '(cons (expr-returning x) (expr-returning y))) 
    ((expr-returning obj) (cond [(null? obj) 'null] 
           [(number? obj) 'obj] 
           [(char? obj) 'obj] 
           [(boolean? obj) 'obj] 
           [(pair? obj) '(cons (expr-returning (car obj)) (expr-returning (cdr obj)))] ; expanded 
           [else 'error] 
           )))) 

そしてdので、それはobjだマクロのシンボルであり、実行時にそれがリテラル式に変身:あなたが実際にあるように、これは式exprを返すの拡大をトリガする評価

'(cons (expr-returning (car d)) (expr-returning (cdr d))) 

評価する(cons '(car (expr-returning d)) '(cdr (expr-returning d)))((car (expr-returning d)) . (cdr (expr-returning d)))となり、((car (expr-returning d)) cdr (expr-returning d))と表示されます

これを再度評価すると、実際に前と同じことをするがあります。実際には、実際にdの構造を得ることは決してありませんが、dという奇妙なループをたどってペアになり、続いて定数をたどり、dのペアに戻ります。

#<procedure: +>のようなリテラルなバージョンを持たないタイプの構造を保持している限り、構造をとり、元の構造体にequal?という何かに評価される式を生成するのは簡単です。 #<struct:bla>。ここでの唯一のペアと数字をサポートするものです。

(define (obj->literal obj) 
    (define (primitive? v) 
    (or (number? v) (null? v))) 
    (list 'quote 
     (let recur ((obj obj)) 
      (if (primitive? obj) 
       obj 
       (cons (recur (car obj)) 
        (recur (cdr obj))))))) 

(define e (obj->literal d)) 
e 
; ==> (cons (cons 'a (cons 'e (cons 'i (cons 'o (cons 'u 'y))))) (cons 'i (cons 'o (cons 'u 'y)))) 
(equal? d (eval e (make-base-namespace))) 
; ==> #t 
+0

私は自分のコードで間違いを犯しました。ループはそこにあるべきではありません。あなたのコードは正しいです。 –

1

お使いの言語の選択肢として#lang racket、 を使用してプログラムを実行する場合は、evalで正しい名前空間を使用する必要があります。

次の例のようにこれを使用することができます。要するに

(define ns (variable-reference->namespace (#%variable-reference))) 
(eval e ns) 

を:あなたのマクロが動作しています。マクロの結果を評価する例はありません(少なくとも#lang racket)。

evalを「モジュール内部」とREPLから使用することには違いがあることにも注意してください。私はRenzoがあなたのサンプルをREPLで正しく動作し、モジュール内から(つまり定義ウィンドウ内で)その例を試したことをテストしたと思います。

+0

はい、名前空間が必要です。 –

関連する問題