Lambdaの実現
2677 ワード
最初はlarvaで前述の解析式とこのlambdaを実現するつもりはありませんでしたが、解析式はループで代用できると思っていたので、lambdaは呼び出し可能なオブジェクトで代用できると思っていましたが、後で気づいたのはやったほうがいいです.結局、この2つのものは便利すぎて、なければコードがくどいです.実は最初に出会った問題はリスト解析式で、私にとってlambdaが使っているところは多くないと思っていたので(多くの人が好んで使っていますが)、リスト解析式を始めたとき、pythonのmap関数をふと思いつき、mapでlambdaに合わせると解析式を実現できる機能なので、先に実現したのはかえってlambdaで、しかし、半分にしたとき、事前に設計されたlambda文法はmapと協力して実現するしかないことに気づいた.for...in...の解析式は、実現できません...for...in...if...,map関数にパラメータを追加しない限り、リスト解析式を振り返ると、リスト、辞書解析式、lambdaがすべて行われます.
文法的にはlarvaのlambdaはpythonと同じですが、メカニズム的に少し修正されています.pythonのlambdaは、式の値を返す匿名関数であり、defと何の違いもありません.すなわち、
Lambdaの2つの言語における重要な違いは、1つの例で表すことができます.
同様のコードはlarvaの下で10個の123を印刷します.larvaはlambdaオブジェクトを生成するときに現在の関数ローカル環境に関連付けられるのではなく、現在の関数ローカル環境にスナップショットを作成します.つまり、自分のオブジェクト内部に保存されたコピーをコピーします.上記pythonの効果を実装するには、次のように変更できます.
なぜこのようにするのかは、以前ネット上でこの問題に関する友人の議論を見たことに由来しています.関連環境が良いのか、コピー環境が良いのか、コピーがより直感的だと思っている人が多いようですが、他の言語のlambdaや閉包がどのように処理されているのかは研究されていません.
Lambdaの実装は前述のリスト、辞書解析式と同様であり、コード内のlambdaごとにクラスが対応し、このクラスには内蔵op_がある.Callメソッド、すなわち関数呼び出し演算「()」のリロード実装です.もちろん、このクラスはLarObjから継承されています.
文法的にはlarvaのlambdaはpythonと同じですが、メカニズム的に少し修正されています.pythonのlambdaは、式の値を返す匿名関数であり、defと何の違いもありません.すなわち、
f = lambda x : x + 1
相当def f(x):
return x + 1
pythonはすべてオブジェクトなので、ここのfは普通の変数で、1つの関数オブジェクトを参照しているので、匿名で関数を使用しない場合は、lambdaの代わりにdefを使用するのが可読性が良いかもしれません.このメカニズムは柔軟ですが、関数の括弧を書くのを忘れた場合は、文法的には間違いありませんが、別の意味です.例えば、ファイルを閉じるときにf.closeと書く人をよく見かけますが、実際にはcloseメソッドオブジェクトに値を求めるだけで、実際に閉じていません.この問題を考慮すると、実際に関数自体がオブジェクトとして使用される場合は相対的に直接呼び出される場合が少なく、larvaは関数、クラス、メソッドなどがオブジェクトではないことを規定している.つまり、単独の式として存在することはできない.1つのオブジェクトのように使用するには、lambdaでカプセル化する必要がある.例えば、g = lambda x : f(x)
ではg(x)を呼び出すのはf(x)に相当しますが、gはオブジェクトですが、fではなく、明示的な構文は関数の非呼び出し使用を強調するのに便利だと思います.Lambdaの2つの言語における重要な違いは、1つの例で表すことができます.
def main():
i = 123
f = lambda : i
for i in range(10):
print f()
pythonでこのコードを実行すると、0から9が印刷されます.なぜなら、このlambdaは閉パッケージ関数であり、このiはmain関数の現在の呼び出しを参照するローカル変数環境であるため、main関数のiが変化すると、呼び出しfはmainのiの値を返します.同様のコードはlarvaの下で10個の123を印刷します.larvaはlambdaオブジェクトを生成するときに現在の関数ローカル環境に関連付けられるのではなく、現在の関数ローカル環境にスナップショットを作成します.つまり、自分のオブジェクト内部に保存されたコピーをコピーします.上記pythonの効果を実装するには、次のように変更できます.
func main():
i = [123]
f = lambda : i[0]
for i[0] in range(10):
print f()
ローカル環境スナップショットをlambdaで保存するときに使用する浅いコピーのため、1つのコンテナで実行できます.なぜこのようにするのかは、以前ネット上でこの問題に関する友人の議論を見たことに由来しています.関連環境が良いのか、コピー環境が良いのか、コピーがより直感的だと思っている人が多いようですが、他の言語のlambdaや閉包がどのように処理されているのかは研究されていません.
Lambdaの実装は前述のリスト、辞書解析式と同様であり、コード内のlambdaごとにクラスが対応し、このクラスには内蔵op_がある.Callメソッド、すなわち関数呼び出し演算「()」のリロード実装です.もちろん、このクラスはLarObjから継承されています.
f = lambda x : x + i
はjavaコードのように実装されます.f = new Lambda_0001(i);
現在の環境、すなわち変数iの値が構築時に入力され、lambdaオブジェクトによって保存され、このlambdaオブジェクトの実装は次のコードに類似している.class Lambda_0001 extends LarObj
{
private LarObj m_i;
Lambda_0001(LarObj i)
{
m_i = i;
}
public LarObj op_call(LarObj x)
{
return x.op_add(m_i);
}
}
でlambdaにグローバル変数やthis/superなどが現れると、処理方式もリスト解析式の実装と一致し、グローバル変数はスナップショットを行わず、呼び出されるたびの実際の値に従って演算に参加し、メソッドでlambdaを使用するとLambda_XXXXクラス実現在対応外部クラス中、this/superのアクセスはjavaがスナップショットを作ったのと同じです