質問
実際は趣味で本を読んでいますが、宿題とみなされるかもしれません。いずれにせよ、この言語ではローカル状態変数にまったく慣れていません...たとえば、次のコードを考えてみましょう。
(define flip
(let ((count 0))
(lambda ()
(if (= 0 count)
(begin (set! count 1) count)
(begin (set! count 0) count)))))
なぜこのコードは 1 と 0 を繰り返すのでしょうか?この関数が呼び出されるたびに、count には 0 の値が与えられます。Python に相当するものは次のようになります。
class Flip:
def __init__(self):
pass
def __call__(self):
count = 0
if count == 0:
count = 1
return count
else:
count = 0
return count
これは毎回同じものを返します。私は混乱しています...
解決
私は、関数型言語のための書き込みコンパイラで少し経験を持っているので、おそらくその関数が格納/メモリ内でどのように表現されるかの簡単な説明が順序です。すべての機能は、大きくEが自由変数の集合であり、Fは、機能自体の「コード」である対(E、F)と考えることができます。関数を呼び出すとき、それはEの値をとり、F内の変数のためのものに置き換え、その後、それらの値を使用してコードを実行します。
あなたの例では、懸念している。ここで、だから、あなたはあなたのlet式で返される関数であることが、変数「フリップ」を定義しています。この関数は、あなたのラムダの内部のものです。 「カウント」ラムダ外で定義されているので、それは自由変数ですので、それは機能の環境に保存されています。その後、あなたは(フリップ)を呼び出すたびに、インタプリタは、ラムダのコードに行く、それは環境の中で、「数」の値をルックアップする必要があると見て、それを変更し、リターン、ことを行います。あなたはそれを呼び出すたびに、「カウント」に格納されている値が解消されない理由です。
それは代わりに、自由変数のバインドされた変数ですので、あなたがしたい場合は、ラムダ内let式を入れて、あなたがフリップを呼び出すたびにゼロであることを数えます。
他のヒント
ラムダはクロージャです。これは自由変数 (count) を参照する関数であり、ローカルに定義されておらず、パラメーターの 1 つでもなく、最も近い囲み字句環境にバインドされています。
呼び出される関数はラムダであり、「フリップ」ではありません。Flip は、(let ...) 式から返されるラムダに付けた名前にすぎません。
Python については、言語はわかりませんが、count はローカル変数ではなく、Flip オブジェクトのメンバーである必要があるようです。 電話.
あなたのフリップ機能は、実際の(ラムダ内で定義されている)の機能を返すので、
あなたが返される関数を呼び出すたびに、それは、その環境を変更します。
あなたが考えてみれば、<全角> は一度だけ(0までカウントし、初期化)環境を作成してみましょう - 。ラムダ関数があなたに返却されたときに、
センスラムダでは、その最後のフレームで初期化された環境を使用していますあなたのための関数オブジェクトを作成します。のみましょう。の単一の変数のカウントと。あなたの関数を呼び出すたびに、それは、その環境を変更します。 あなたがのフリップの第二の時間をコールした場合には、異なる環境を持つ別の関数オブジェクトを返します。 (0に初期化カウント)あなたはその後、独立して2つのファンクタを切り替えることができます。
あなたはそれはあなたが にenvironmantalモデルについてお読みください。
働く完全にどのようにundestandしたい場合それはもっと似ています
class Flip:
def __init__(self):
self.count = 0
def __call__(self):
if self.count == 0:
self.count = 1
return self.count
else:
self.count = 0
return self.count
追加の説明を追加して更新します。Scheme の関数は、自由変数の周囲を「閉じる」クロージャです。 count
, 、その外側のスコープで定義されます。その方法 count
で定義されています let
本体として関数のみを使用すると、その関数がそれにアクセスできる唯一のものであることを意味します。 count
これは事実上、関数に関連付けられた一種のプライベートな可変状態です。
これは、SICP の Scheme で「オブジェクト」が伝統的に作成される方法です。 let
一連の変数 (初期値に初期化されたインスタンス変数) を定義し、本体内でインスタンス変数への共有アクセスを持つ「メソッド」である一連の関数を定義します。そのため、ここでは、何が起こっているかを表すために Python クラスを使用するのが自然です。 count
インスタンス変数であること。
Python 3.x へのより文字通りの翻訳は次のようになります (Python には let
(限定スコープローカル変数宣言) 構文と Python の lambda
はステートメントを受け取らないため使用できません):
count = 0
def flip():
nonlocal count
if count == 0:
count = 1
return count
else:
count = 0
return count
# pretend count isn't in scope after this
元のコードの問題は、それが不可欠なスタイルの強い影響力を持っていることです。より多くの慣用的な解決策は次のようになります。
(define (flip)
(let ((flag #t))
(lambda ()
(set! flag (not flag))
(if flag 1 0))))
oobooコメントあなたに質問に答えるために、あなたは
機能を返す関数をしたいです(define make-flipper
(lambda ()
(let ((count 0))
(lambda ()
(let ((v count))
(set! count (- 1 count))
v)))))
;; test it
(let ((flip-1 (make-flipper)))
(format #t "~s~%" (flip-1))
(format #t "~s~%" (flip-1))
(format #t "~s~%" (flip-1))
(let ((flip-2 (make-flipper)))
(format #t "~s~%" (flip-2))
(format #t "~s~%" (flip-2))
(format #t "~s~%" (flip-2))))
あなたは自明のセットを変更することができます!ラインは、カウンタではなく、フリッパー(より有用)となるように