2016-08-08 3 views
0

私はCommon LispからChicken Schemeに移動しようとしていますが、問題はたくさんあります。チキンスキームマクロから他のマクロを呼び出すには?

現在の問題は次のとおりです。他のマクロを呼び出すマクロ(おそらくdefine-syntaxを使用していますか?)を書くにはどうすればよいですか?スキームでは、同等のコードが動作しないのに対し

(defmacro append-to (var value) 
`(setf ,var (append ,var ,value))) 

(defmacro something-else() 
(let ((values (list)) 
    (append-to values '(1))))) 

:Common Lispの中で、私はこのような何かを行うことができますたとえば

(define-syntax append-to 
(syntax-rules() 
    ((_ var value) 
    (set! var (append var value))))) 

(define-syntax something-else 
(syntax-rules() 
    ((_) 
    (let ((values (list))) 
    (append-to values '(1)))))) 

append-toマクロから呼び出すことはできませんsomething-elseマクロ。 append-to「変数」が定義されていないとエラーが表示されます。

私はGoogleや他のソースから収集したすべての情報によれば、マクロは閉じた環境で他のコードにアクセスすることなく評価されます。本質的に、マクロが評価されるときには、組み込みのScheme関数とマクロを除き、他のものは存在しません。私はer-macro-transformersyntax-case(これは現在Chickenでは推奨されていません)、さらにはprocedural-macrosモジュールを使用しようとしました。

確かにマクロの全体の目的は、それらがコードの繰り返しを避けるために、のマクロに基づいて構築されていることです。もしマクロが孤立して書かれなければならないのであれば、私の心にはあまり意味がありません。

私は他のSchemeの実装を調査しましたが、それ以上の運がありませんでした。それは単にできないと思われる。

誰か助けてもらえますか?

+0

'syntax-rules'マクロよりも複雑なことは、非標準的なSchemeなので、あなたがしたいことは多くの* specific * Schemesでかなり可能ですが、行う方法は多分様々です。この種の質問をしたいのであれば、具体的なSchemeの実装を選び、それをどのように複製するかを尋ねるほうが良いでしょう。 –

+0

@AlexisKingありがとう、私は1つの実装にもっと焦点を当てるように私の質問を修正しました。 –

+0

私はその質問をよく理解していません。おそらく、あなたはCHICKENで作業することができないCommon Lispの例を与えることができますか? – sjamaan

答えて

2

実行時に拡張時間を混乱させるようです。 syntax-rulesの例ではをlet + setに展開します。つまり、実行時にappendが実行されます。

syntax-rulesは、何も展開されなくなるまで、マクロを展開して特定の出力に入力を書き換えます。展開時に実際に計算を実行したい場合は、手続き型マクロを使用するしかありません(これはCLのdefmacroの例でも起こります)。

評価レベルは厳密に分離されているので、プロシージャはマクロを使用できますが、マクロ自体は同じコードで定義されたプロシージャ(またはマクロ)を使用できません。 use-for-syntaxを使用して、手続き型マクロで使用するために、プロシージャおよびマクロをモジュールからロードできます。構文拡張時に実行するものを定義するための限定的なサポートは、begin-for-syntaxにラップすることによって制限されています。

例えばthis SO questionまたはthis discussion on the ikarus-users mailing listを参照してください。 Matthew Flattの論文composable and compilable macrosは、これの背後にある理論について詳しく説明しています。

"相分離"の考え方は、Schemeの世界では比較的新しいものです(Flattの論文は2002年のものです)ので、Schemeのコミュニティではかなり混乱している人がかなりいます。Schemeが長い間マクロを持っていたにもかかわらず、新しいマクロの理由は、手続き型マクロは、R6RS(そしてsyntax-caseはむしろ議論の余地があるのでR7RSで元に戻った)から標準の一部になっただけなので、厳格に指定する必要があるこれまで問題になっていません。コンパイル時と実行時をまとめてSchemeの "伝統的な" Lispy実装の場合、これは決して問題ではありませんでした。いつでもコードを実行できます。動作するはず

(begin-for-syntax 
    (define-syntax append-to 
    (ir-macro-transformer 
     (lambda (e i c) 
     (let ((var (cadr e)) 
       (val (caddr e))) 
      `(set! ,var (append ,var ,val))))))) 

(define-syntax something-else 
    (ir-macro-transformer 
    (lambda (e i c) 
     (let ((vals (list 'print))) 
     (append-to vals '(1)) 
     vals)))) 

(something-else) ; Expands to (print 1) 

あなたは、独自のモジュールにappend-toの定義を置く場合、あなたuse-for-syntaxそれは、:

戻ってあなたの例を取得するあなたは正しく相を分離すれば、それは正常に動作します同じように。これにより、コード本体とプロシージャで定義したマクロの両方で、同じモジュールを使用することもできます。useuse-for-syntaxの両方の式が必要です。

+0

これは非常に便利な返事でした。ありがとうございました。だから...ちょっと[this](http://pastebin.com/weP9GnR1)のように? –

+0

しかし、その特定の例では、もちろん、マクロトランスを使用する必要はありません。これは、副作用を実行する必要がある場合、またはコンパイル時に識別子または定数を構築する必要がある場合にのみ必要です。 (入力式のパターンマッチと再配置が必要な場合は 'syntax-rules'を使うだけです) – sjamaan

関連する問題