comp-sciの背景がない人にとって、コンピュータサイエンスの世界でのラムダとは何ですか?
comp-sciの背景がない人にとって、コンピュータサイエンスの世界でのラムダとは何ですか?
回答:
ラムダはラムダ計算から来ており、プログラミングにおける無名関数を指します。
なぜこれがクールなのですか?名前を付けなくても、使い捨ての関数をすばやく作成できます。また、クロージャーを作成するための優れた方法を提供します。その力であなたはこのようなことをすることができます。
パイソン
def adder(x):
return lambda y: x + y
add5 = adder(5)
add5(1)
6
Pythonのスニペットからわかるように、関数adderは引数xを受け取り、別の引数yを受け取る無名関数またはラムダを返します。その無名関数を使用すると、関数から関数を作成できます。これは簡単な例ですが、ラムダとクロージャが持つ力を伝えているはずです。
他の言語の例
Perl 5
sub adder {
my ($x) = @_;
return sub {
my ($y) = @_;
$x + $y
}
}
my $add5 = adder(5);
print &$add5(1) == 6 ? "ok\n" : "not ok\n";
JavaScript
var adder = function (x) {
return function (y) {
return x + y;
};
};
add5 = adder(5);
add5(1) == 6
JavaScript(ES6)
const adder = x => y => x + y;
add5 = adder(5);
add5(1) == 6
スキーム
(define adder
(lambda (x)
(lambda (y)
(+ x y))))
(define add5
(adder 5))
(add5 1)
6
Func<int, Func<int, int>> adder =
(int x) => (int y) => x + y; // `int` declarations optional
Func<int, int> add5 = adder(5);
var add6 = adder(6); // Using implicit typing
Debug.Assert(add5(1) == 6);
Debug.Assert(add6(-1) == 5);
// Closure example
int yEnclosed = 1;
Func<int, int> addWithClosure =
(x) => x + yEnclosed;
Debug.Assert(addWithClosure(2) == 3);
迅速
func adder(x: Int) -> (Int) -> Int{
return { y in x + y }
}
let add5 = adder(5)
add5(1)
6
PHP
$a = 1;
$b = 2;
$lambda = fn () => $a + $b;
echo $lambda();
ハスケル
(\x y -> x + y)
Javaはこの記事を参照してください
// The following is an example of Predicate :
// a functional interface that takes an argument
// and returns a boolean primitive type.
Predicate<Integer> pred = x -> x % 2 == 0; // Tests if the parameter is even.
boolean result = pred.test(4); // true
ルア
adder = function(x)
return function(y)
return x + y
end
end
add5 = adder(5)
add5(1) == 6 -- true
コトリン
val pred = { x: Int -> x % 2 == 0 }
val result = pred(4) // true
ルビー
Rubyは、関数を呼び出すのとまったく同じ構文を使用してラムダを呼び出すことができないという点で少し異なりますが、ラムダはまだあります。
def adder(x)
lambda { |y| x + y }
end
add5 = adder(5)
add5[1] == 6
RubyはRubyなので、ラムダの省略形があるため、次のように定義できますadder
。
def adder(x)
-> y { x + y }
end
R
adder <- function(x) {
function(y) x + y
}
add5 <- adder(5)
add5(1)
#> [1] 6
ラムダはインラインで定義される関数の一種です。ラムダに加えて、通常、関数やラムダなどへの参照を保持できる、ある種の変数タイプもあります。
たとえば、ラムダを使用しないC#コードは次のとおりです。
public Int32 Add(Int32 a, Int32 b)
{
return a + b;
}
public Int32 Sub(Int32 a, Int32 b)
{
return a - b;
}
public delegate Int32 Op(Int32 a, Int32 b);
public void Calculator(Int32 a, Int32 b, Op op)
{
Console.WriteLine("Calculator: op(" + a + ", " + b + ") = " + op(a, b));
}
public void Test()
{
Calculator(10, 23, Add);
Calculator(10, 23, Sub);
}
これはCalculatorを呼び出し、2つの数値だけでなく、計算結果を取得するためにCalculator内で呼び出すメソッドを渡します。
C#2.0では、無名メソッドを取得しました。これにより、上記のコードが次のように短縮されます。
public delegate Int32 Op(Int32 a, Int32 b);
public void Calculator(Int32 a, Int32 b, Op op)
{
Console.WriteLine("Calculator: op(" + a + ", " + b + ") = " + op(a, b));
}
public void Test()
{
Calculator(10, 23, delegate(Int32 a, Int32 b)
{
return a + b;
});
Calculator(10, 23, delegate(Int32 a, Int32 b)
{
return a - b;
});
}
そして、C#3.0ではラムダを取得して、コードをさらに短くしました。
public delegate Int32 Op(Int32 a, Int32 b);
public void Calculator(Int32 a, Int32 b, Op op)
{
Console.WriteLine("Calculator: op(" + a + ", " + b + ") = " + op(a, b));
}
public void Test()
{
Calculator(10, 23, (a, b) => a + b);
Calculator(10, 23, (a, b) => a - b);
}
Op
単に使用してもよいFunc<int, int>
Console.WriteLine("Calculator: op " + op.Method.Name + " (" + a + ", " + b + ") = " + op(a, b));
最初の例をお勧めします。
「ラムダ」という名前は単なる歴史的な遺物です。私たちが話しているのは、その値が関数である式です。
簡単な例(次の行にScalaを使用)は次のとおりです。
args.foreach(arg => println(arg))
ここで、メソッドへの引数foreach
は無名関数の式です。上記の行は多かれ少なかれこのようなものを書くことと同じです(かなり実際のコードではありませんが、あなたはアイデアを得るでしょう):
void printThat(Object that) {
println(that)
}
...
args.foreach(printThat)
あなたが気にする必要がないことを除いて:
関数値に慣れると、次のようにすべての式に名前を付ける必要があるのと同じくらい、値なしで実行する必要があります。
int tempVar = 2 * a + b
...
println(tempVar)
必要な場所に式を記述するだけではなく、
println(2 * a + b)
正確な表記は言語によって異なります。ギリシャ語は必ずしも必要ではありません!;-)
これは、ラムダ計算を参照します。これは、ラムダ式のみを持つ正式なシステムであり、唯一の引数として関数を取り、関数を返す関数を表します。ラムダ計算のすべての関数はその型、すなわちですλ : λ → λ
。
Lispはラムダの概念を使用して、その無名関数リテラルに名前を付けました。このラムダは、xとyの2つの引数を取り、その積を返す関数を表します。
(lambda (x y) (* x y))
次のようにインラインで適用できます(50と評価されます):
((lambda (x y) (* x y)) 5 10)
λ : λ -> λ
は混乱していると思います(実際には無効です)。
ラムダ計算は、置換の一貫した数学的理論です。学校の数学では、たとえばx+y=5
とペアになりx−y=1
ます。個々の方程式を操作する方法に加えて、方程式間の置換が論理的に行われていれば、これら2つの情報をまとめることもできます。ラムダ計算は、これらの置換を行う正しい方法を体系化しています。
y = x−1
これが2番目の方程式の有効な再配置であることを考えると、これλ y = x−1
は、シンボルの代わりにシンボルx−1
を使用する関数を意味しますy
。λ y
最初の方程式の各項に適用することを想像してください。用語がy
その後である場合、置換を実行します。それ以外の場合は何もしません。これを紙の上でλ y
行うと、それを適用すると最初の方程式が解けるようになります。
これは、コンピュータサイエンスやプログラミングなしの答えです。
私が考えることができる最も単純なプログラミングの例は、http://en.wikipedia.org/wiki/Joy_( programming_language)#How_it_worksからのものです。
以下は、命令型プログラミング言語(C)で二乗関数を定義する方法です。
int square(int x) { return x * x; }
変数xは、関数が呼び出されたときに平方される実際の値に置き換えられる仮パラメーターです。関数型言語(Scheme)では、同じ関数が定義されます。
(define square (lambda (x) (* x x)))
これは多くの点で異なりますが、仮パラメーターxを同じように使用します。
追加: http : //imgur.com/a/XBHub
少し単純化しすぎています:ラムダ関数は他の関数に渡して渡すことができ、そのロジックにアクセスできます。
C#では、ラムダ構文は匿名デリゲートと同じ方法で単純なメソッドにコンパイルされることがよくありますが、分解してそのロジックを読み取ることもできます。
たとえば(C#3の場合):
LinqToSqlContext.Where(
row => row.FieldName > 15 );
LinqToSqlはその関数(x> 15)を読み取り、実際のSQLに変換して式ツリーを使用して実行できます。
上記のステートメントは次のようになります。
select ... from [tablename]
where [FieldName] > 15 --this line was 'read' from the lambda function
これは、通常のメソッドや匿名デリゲート(実際には単なるコンパイラマジック)とは異なり、読み取ることができません。
C#でラムダ構文を使用するすべてのメソッドを式ツリー(つまり、実際のラムダ関数)にコンパイルできるわけではありません。例えば:
LinqToSqlContext.Where(
row => SomeComplexCheck( row.FieldName ) );
現在、式ツリーを読み取ることができません-SomeComplexCheckを分解できません。SQLステートメントはwhereなしで実行され、データのすべての行が通過しSomeComplexCheck
ます。
ラムダ関数を無名メソッドと混同しないでください。例えば:
LinqToSqlContext.Where(
delegate ( DataRow row ) {
return row.FieldName > 15;
} );
これには「インライン」関数もありますが、今回は単なるコンパイラの魔法です-C#コンパイラはこれを自動生成された名前を持つ新しいインスタンスメソッドに分割します。
匿名メソッドは読み取ることができないため、ラムダ関数の場合のようにロジックを変換することはできません。
この記事のLambdasの説明が気に入っています:LINQの進化とC#の設計への影響。ラムダスの実際の世界を示し、それを実用的な例として構築しているので、それは私には非常に理にかなっています。
彼らの簡単な説明:ラムダは、コード(関数)をデータとして扱う方法です。
Rubyのラムダの例は次のとおりです。
hello = lambda do
puts('Hello')
puts('I am inside a proc')
end
hello.call
次の出力を生成します:
Hello
I am inside a proc
@Brian C#、LINQおよび非LINQ演算子では常にラムダを使用します。例:
string[] GetCustomerNames(IEnumerable<Customer> customers)
{ return customers.Select(c=>c.Name);
}
C#の前は、AJAX関数へのコールバックにJavaScriptで匿名関数を使用していました。
getXmlFromServer(function(result) {/*success*/}, function(error){/*fail*/});
ただし、C#のラムダ構文の興味深い点は、それ自体では型を推測できない(つまり、var foo =(x、y)=> x * yと入力できない)が、その型によっては割り当てられると、それらは式を表すデリゲートまたは抽象構文ツリーとしてコンパイルされます(これは、LINQオブジェクトマッパーが「言語統合」マジックを行う方法です)。
LISPのラムダは、引用演算子に渡され、リストのリストとしてトラバースすることもできます。一部の強力なマクロはこの方法で作成されます。
質問は正式に大いに回答されているので、これについてはこれ以上付け加えません。
数学やプログラミングについてほとんど、またはまったく知らない人に非常にシンプルで非公式の言葉で、私はそれを、いくつかの入力を受け取り、いくつかの作業を行い、いくつかの出力を生成し、特定の名前を持たない小さな「マシン」または「ボックス」として説明します、しかし私たちはそれがどこにあるかを知っており、この知識だけでそれを使用します。
実際的に言えば、関数が何であるかを知っている人にとって、それは名前のない関数であり、通常はメモリを参照するだけで使用できるメモリ内のポイントに置かれる関数であることを伝えます(通常、変数-彼らが関数ポインターの概念について聞いた場合、私はそれらを同様の概念として使用します)-この回答はかなりの基本(クロージャーなどの言及なし)をカバーしますが、簡単にポイントを得ることができます。
あなたはそれを無名関数と考えることができます-ここにいくつかの詳細があります:ウィキペディア-無名関数
マクロ置換と、ExecScript {}およびEvaluate()関数を使用しているVisual FoxProで作業しているため、ラムダ式に頭を抱え込むのに問題があります。
? Calculator(10, 23, "a + b")
? Calculator(10, 23, "a - b");
FUNCTION Calculator(a, b, op)
RETURN Evaluate(op)
正式なラムダを使用することの明確な利点の1つは、(私は)コンパイル時のチェックです。Foxは、実行しようとするまで、上記のテキスト文字列を入力したかどうかを認識しません。
これは、データ駆動型コードにも役立ちます。ルーチン全体をデータベースのメモフィールドに格納して、実行時に評価するだけです。これにより、実際にソースにアクセスすることなく、アプリケーションの一部を調整できます。(しかし、それは完全に別のトピックです。)
comp-sciの背景がない人にとって、コンピュータサイエンスの世界でのラムダとは何ですか?
シンプルで読みやすいpythonコードを使用して、一歩一歩直感的に説明します。
つまり、ラムダは匿名のインライン関数です。
lambdas
基本的な計算の背景を持つ新入生として理解するために、割り当てから始めましょう。
割り当ての青写真は「名前=値」です。以下を参照してください。
In [1]: x = 1
...: y = 'value'
In [2]: x
Out[2]: 1
In [3]: y
Out[3]: 'value'
「x」、「y」は名前、1、「値」は値です。数学の関数を試す
In [4]: m = n**2 + 2*n + 1
NameError: name 'n' is not defined
エラーレポート。
コードとして数学を直接記述することはできません。「n」を定義するか、値に割り当てる必要があります。
In [8]: n = 3.14
In [9]: m = n**2 + 2*n + 1
In [10]: m
Out[10]: 17.1396
2つの分離したラインを1つに結合することを主張するとどうなるでしょうか。来るlambda
In [13]: j = lambda i: i**2 + 2*i + 1
In [14]: j
Out[14]: <function __main__.<lambda>>
エラーは報告されていません。
これは一目でlambda
わかります。数学で行うように、関数を1行で直接コンピューターに書き込むことができます。
後で見ます。
「割り当て」についてさらに掘り下げていきましょう。
上に示したように、等号=
は単純なデータ(1および '値')タイプと単純な式(n ** 2 + 2 * n + 1)で機能します。
これを試して:
In [15]: x = print('This is a x')
This is a x
In [16]: x
In [17]: x = input('Enter a x: ')
Enter a x: x
シンプルなステートメントで機能します。Python7には11種類あります。シンプルなステートメント— Python 3.6.3ドキュメント
複合ステートメントはどうですか
In [18]: m = n**2 + 2*n + 1 if n > 0
SyntaxError: invalid syntax
#or
In [19]: m = n**2 + 2*n + 1, if n > 0
SyntaxError: invalid syntax
それが機能するdef
ことを可能にします
In [23]: def m(n):
...: if n > 0:
...: return n**2 + 2*n + 1
...:
In [24]: m(2)
Out[24]: 9
多田、それを分析して、「m」は名前、「n ** 2 + 2 * n + 1」は値です。:
「=」の変形です。
理解するためだけに、すべてが割り当てから始まり、すべてが割り当てであることを確認してください。
ここでに戻ります。lambda
「m」という名前の関数があります。
試してください:
In [28]: m = m(3)
In [29]: m
Out[29]: 16
ここには「m」の名前が2つあります。関数にはm
すでに重複した名前があります。
それは次のようなフォーマットです:
In [27]: m = def m(n):
...: if n > 0:
...: return n**2 + 2*n + 1
SyntaxError: invalid syntax
それは賢い戦略ではないので、エラーレポート
それらの1つを削除し、名前なしで関数を設定する必要があります。
m = lambda n:n**2 + 2*n + 1
「無名関数」と呼ばれています
結論として、
lambda
数学の場合と同様に、関数を1つの直線で記述できるインライン関数内lambda
匿名ですお役に立てれば。
JavaScriptでは、例えば、機能は他のすべてと同じ混合型として扱われ(int
、string
、float
、bool
)。そのため、関数をその場で作成し、それらを物事に割り当て、後で呼び出すことができます。それは便利ですが、使いすぎたくないものではありません。そうしないと、コードを保守しなければならない人を混乱させてしまいます...
これは、このうさぎの穴がどの程度深くなるかを確認するために私が遊んでいたコードです。
var x = new Object;
x.thingy = new Array();
x.thingy[0] = function(){ return function(){ return function(){ alert('index 0 pressed'); }; }; }
x.thingy[1] = function(){ return function(){ return function(){ alert('index 1 pressed'); }; }; }
x.thingy[2] = function(){ return function(){ return function(){ alert('index 2 pressed'); }; }; }
for(var i=0 ;i<3; i++)
x.thingy[i]()()();
CSのコンテキストでは、ラムダ関数は、数式の記号評価の問題に取り組む抽象的な数学概念です。そのコンテキストでは、ラムダ関数はラムダ項と同じです。
しかし、プログラミング言語では、それは何か違うものです。これは「インプレース」で宣言されたコードの一部であり、「ファーストクラスの市民」として渡すことができます。この概念は有用であるように思われたので、ほとんどすべての人気のある現代のプログラミング言語に取り入れられました(ラムダ関数のこれまでの投稿を参照)。
A
Lambda Function
、またはSmall Anonymous Function
、周囲に合格し、あなたのコード内で使用可能な機能の自己完結型ブロックです。-ラムダは異なるプログラミング言語で異なる名前があるLambda
ではPythonやKotlin、Closure
中スウィフト、またはBlock
でCとObjective-Cのを。ラムダの意味はこれらの言語で非常に似ていますが、時々若干の違いがあります。
let coffee: [String] = ["Cappuccino", "Espresso", "Latte", "Ristretto"]
func backward(_ n1: String, _ n2: String) -> Bool {
return n1 > n2
}
var reverseOrder = coffee.sorted(by: backward)
// RESULT: ["Ristretto", "Latte", "Espresso", "Cappuccino"]
reverseOrder = coffee.sorted(by: { (n1: String, n2: String) -> Bool in
return n1 > n2
})
reverseOrder = coffee.sorted(by: { (n1: String, n2: String) -> Bool in return n1 > n2 } )
reverseOrder = coffee.sorted(by: { n1, n2 in return n1 > n2 } )
reverseOrder = coffee.sorted(by: { n1, n2 in n1 > n2 } )
reverseOrder = coffee.sorted(by: { $0 > $1 } )
// $0 and $1 are closure’s first and second String arguments.
reverseOrder = coffee.sorted(by: >)
// RESULT: ["Ristretto", "Latte", "Espresso", "Cappuccino"]
お役に立てれば。
私も手に入れました。私はこれをJSで試しました:
var addAndMult = function(x) {
return (function(y) {
return (function(z) {
return (x+y)*z;
});
});
};
2から4を追加し、結果を6で乗算します。ただし、読みにくい場合があります:(
また、興味深いforEach関数を作成しました。
var forEach = function(arr) {
return (function(x) {
for (var i=0; arr[i]; i++) {
x(arr[i]);
}
});
}
forEach([1,2,3,4,5])(console.log);
このメソッドは、配列を反復してアクションを実行します-コンソールに出力する場合。今、私もlabmdasが強力な理由を理解しています。
コンピュータプログラミングでは、ラムダは外部ソースからいくつかの引数をとるコード(ステートメント、式、またはそれらのグループ)です。それは常に無名関数である必要はありません-それらを実装する多くの方法があります。
数学者にはない、式、ステートメント、関数の明確な分離があります。
プログラミングにおける「関数」という言葉も異なります-「関数は実行する一連のステップ」です(ラテン語の「実行」から)。数学では、それは変数間の相関についての何かです。
関数型言語は可能な限り数式に類似するように努めており、それらの単語はほとんど同じ意味です。しかし、他のプログラミング言語ではそれが異なります。
質問は完全に回答されています。詳細については説明しません。錆びて数値計算を書くときの使い方を共有したい。
ラムダ(無名関数)の例があります
let f = |x: f32| -> f32 { x * x - 2.0 };
let df = |x: f32| -> f32 { 2.0 * x };
ニュートン・ラフソン法のモジュールを書いているとき、それは一次および二次導関数として使用されていました。(ニュートンラフソン法とは何か知りたい場合は、「https://en.wikipedia.org/wiki/Newton%27s_method」にアクセスしてください。
次のような出力
println!("f={:.6} df={:.6}", f(10.0), df(10.0))
f=98.000000 df=20.000000
配達オプション付きのレストランがあり、30分以内に完了する必要のある注文があるとします。重要なのは、食事を暖かく縛りつけておく限り、車や裸足で自転車で食べ物を送っても、クライアントは通常気にしません。それでは、このイディオムを匿名で定義されたトランスポート関数を使用してJavascriptに変換してみましょう。
以下では、デリバリーの方法を定義します。つまり、関数に名前を定義します。
// ES5
var food = function withBike(kebap, coke) {
return (kebap + coke);
};
この転送を達成するために矢印/ラムダ関数を使用するとどうなるでしょうか。
// ES6
const food = (kebap, coke) => { return kebap + coke };
クライアントに違いはなく、食べ物を送る方法を考えるのに時間を費やすこともありません。送信してください。
ところで、コーラ付きのケバップはお勧めしません。これが、上位コードがエラーを出す理由です。楽しんで。