2011-01-12 5 views
7

私はいくつかの概念に慣れるために、RubyにLISPの基本バージョンを実装しています。私はPeter NorvigのLispy(http://norvig.com/lispy.html)の実装をベースにしています。私のLISPを書くのに役立ちます:) LISP環境、Rubyハッシュ

私はかかわらず、ここに欠けている、と私はいくつかの助けをいただければと思います何か...

は、次のように彼はPythonの辞書のサブクラスであります。

class Env(dict): 
    "An environment: a dict of {'var':val} pairs, with an outer Env." 
    def __init__(self, parms=(), args=(), outer=None): 
     self.update(zip(parms,args)) 
     self.outer = outer 
    def find(self, var): 
     "Find the innermost Env where var appears." 
     return self if var in self else self.outer.find(var) 

彼はその後、彼は理由を説明するために行きますこれはちょうどdictを使用するよりむしろ。しかし何らかの理由で、彼の説明は私の目を通って頭の後ろを通って流れ続けます。

dictを使用せず、eval関数の中で、新しい "サブ環境"を作成する必要がある場合は、既存のdictを取り出し、更新が必要なキーと値のペアを更新して、次のevalへの新しいディクテーション?

Pythonインタプリタは以前の「外側」のenvを追跡しませんか?また、再帰の性質によって、値が "内側"から "外側"に引き出されることはありませんか?

私はRubyを使用しています。この方法で実装しようとしました。何かがうまくいかず、それが原因かもしれないし、そうでないかもしれない。当然の事項は、「ラムダ」です

def eval(x, env = $global_env) 
    ........ 
    elsif x[0] == "lambda" then 
    ->(*args) { eval(x[2], env.merge(Hash[*x[1].zip(args).flatten(1)])) } 
    ........ 
end 

ライン:ここに私のeval関数、envを定期的にハッシュさです。

機能的な違いがある場合は、私がここでやっていることとNorvigがEnvクラスで行ったこととの間に何が重要な違いがありますか?誰かが私に二人が逸脱するケースを説明することはできますか?

違いがなければ、NorvigがEnvクラスを使用する理由について、誰かが私に啓発することができます。ありがとう:)

+0

Schemeを理解する最も良い方法は、Schemeを実装することです! – erjiang

+0

ああ、本当に... :) – MikeC8

答えて

5

あなたのLispの変数バインディングが不変の場合、環境をコピーすることはそれらをリンクすることと同じです。 increment-i(それがコピーであるため)Sの環境がmainの完全に独立している "の場合は、iの変異はmainには表示されませんし、上記のコードは0を返します

(define main 
    (lambda() 
    (define i 0) 
    (define increment-i 
     (lambda() 
     (set! i (+ i 1)))) 
    (increment-i) 
    i)) 

(main) 

:しかし、次の場合を考えます。一方、環境がリンクされている場合、戻り値は期待通りに1になります。

+0

ああ、それはそれだと思います。ありがとうございました! – MikeC8

1

私のPythonはそれほど良くなく、私のLispはむしろ錆びますが、何が起こっているのかを推測します。ポインタを持たないと主張する言語でも、ポインタから離れることはできません。

dictのコピーは作成されません。参照のコピーを作成するだけで、参照する2つの参照(AKA変数) at)同じ基本オブジェクト。何が起こるかというと、基本的にはこれの変種です:

a = [ 'a', 'b', 'c' ] 
b = a 
a[1] = 'x' 

puts a 
# => ["a", "x", "c"] 
puts b  
# => ["a", "x", "c"] 

Envクラスは環境がfind方法を知ってなくても、外部環境にアクセスすることができますしながら、外部環境を変更することなく、eval内部で修正することができます。また、変更は内部環境の内部で終了し、それらの変更は外部環境の対応する値をマスクします。 get操作は、ローカル環境と外部環境にアクセスし、設定操作は内部環境のみを変更します。

Envは、オブジェクトレベル(クラスレベルではなく)ファサードと呼ぶことができます。

私はあなたのルビー実装に何が問題なのかよく分かりませんが、環境ハッシュの修正コピーを作っているようです。あなたは「何かがうまくいかない」ことを明確にすることはできますか?

説明:Envはシンボルテーブルです。 findのラッピング/リダイレクト機能を使用すると、外側のシンボルテーブルにアクセスすることができますが、新しいシンボルを追加することから保護します。新しいシンボルは内側のシンボルテーブルにのみ追加されます。 Envは基本的にクロージャを管理します。

+0

あなたの返事をありがとう、それは理にかなっています。しかし、この例ではこれが当てはまるとは思わない。なぜなら、AFAIKの "merge"は新しいハッシュを作成し、古いものはそのまま残すからだ。私が間違っている場合、誰かが私をここで修正します:) – MikeC8

+0

Rubyのハッシュ#mergeは新しいハッシュを返します(http://www.ruby-doc.org/core/classes/Hash.html#M000759)ので、私はその部分を取っていきます私の答えのうち。たぶんあなたは「何かがうまくいかない」よりも少し具体的かもしれません。 –

+0

さて、それに入る価値はありません...私は実際にinterpの部分を修正する方法について実際には尋ねていません。それはうまくいきません - むしろ私は主にNorvigがEnvクラスを作った理由について興味があります。 – MikeC8

関連する問題