13

ラムダ式の自由変数を理解する方法を知っている人はいますか?自由変数は、ラムダパラメーターの一部ではない変数です。

私の現在の方法(私はどこにも行きません)は、単にcarとcdrを使用して式を実行することです。私の主な問題は、値が変数であるか、それともスキームプリミティブの1つであるかを把握することです。何かがスキームの組み込み関数の1つに評価されるかどうかをテストする方法はありますか?例えば:

(is-scheme-primitive? 'and)
;Value: #t

MITスキームを使用しています。

4

2 に答える 2

6

任意の MIT スキーム プログラムの場合、これを行う方法はありません。1 つの問題は、説明した関数が機能しないことです。たとえば、これは「スキーム プリミティブ」を使用しませんand

(let ((and 7)) (+ and 1))

しかし、それは確かにシンボルを使用しています'and

もう 1 つの問題は、 のような多くのものは、andマクロで実装される特殊なフォームであることです。プログラムでどの変数が使用されているかを把握するには、プログラム内のすべてのマクロが展開されて何になるかを知る必要があります。

これを機能させるには、入力として受け入れるプログラムのセットを制限する必要があります。最善の選択は、「完全に拡張された」プログラムに限定することです。つまり、関数への入力にマクロの使用が残っていないことを確認する必要がありますfree-variables

これを行うには、expand多くの Scheme システムが提供する機能を使用できます。残念ながら、オンライン ドキュメントから、 MIT スキームがこの機能を提供しているようには見えません。別のシステムを使用できる場合、Racketexpand機能を提供し、local-expandマクロ内で正しく動作します。

free-variablesRacket は実際に、ユーザーが要求する関数の実装も提供します。これには、前述したように、完全に展開されたプログラムを入力 ( または の出力など) として必要としexpandますlocal-expandソースコードも見ることができます。

ソース コードの完全な展開に伴う問題の詳細については、Flatt、Culpepper、Darais、および Findler による次の論文を参照してください。

于 2012-04-29T12:47:54.320 に答える
3

[編集 4] 免責事項。または、1年後に振り返ってみると:

これは実際には、この問題を解決するための非常に悪い方法です。これは、OP の基本的な目標を達成する非常に迅速で汚い方法として機能しますが、「実際の」ユースケースには耐えられません。理由については、この回答のコメントと他の回答のディスカッションを参照してください。

[/編集]

このソリューションはおそらく理想的ではありませんが、mit-scheme の REPL 環境で指定したい任意のラムダ形式で機能します(編集を参照)。私が使用した手順のドキュメントは、mit.edu doc サイトにあります。 get-vars引用符を取り、lambdaペアのリストを返します。各ペアの最初の要素はシンボルで、2 番目の要素は によって返される値environment-reference-typeです。

(define (flatten lst)
  (cond ((null? lst) ())
        ((pair? (car lst)) (append (flatten (car lst)) (flatten (cdr lst))))
        (else
          (cons (car lst) (flatten (cdr lst))))))

(define (get-free-vars proc-form)
  (let ((env (ge (eval proc-form user-initial-environment))))
    (let loop ((pf (flatten proc-form))
               (out ()))
      (cond ((null? pf) out)
            ((symbol? (car pf))
             (loop (cdr pf) (cons (cons (car pf) (environment-reference-type env (car pf))) out)))
            (else
              (loop (cdr pf) out))))))

編集:使用例:

(define a 100)

(get-vars '(lambda (x) (* x a g)))
 => ((g . unbound) (a . normal) (x . unbound) (* . normal) (x . unbound) (lambda . macro))

environment-reference-type編集 2: コードを変更して、シンボル以外の何かで呼び出されることを防ぐようにしました。

編集 3: サムがコメントで指摘したように、これは、ラムダの下の let にバインドされたシンボルが値を持つものとして表示されません..これに対する簡単な修正があるかどうかはわかりません。したがって、これに関する私の声明lambdaは間違っており、「新しいバインディングフォームを含まない単純なもの」のように読むべきlambdaでした...まあ。

于 2012-04-29T17:29:39.240 に答える