对于一个没有计算机科学背景的人来说,计算机科学界的lambda是什么?
lambda来自lambda微积分,在编程中引用匿名函数。
为什么这么酷?它允许您在不命名的情况下编写快速丢弃函数。它还提供了一种编写闭包的好方法。有了这种能力,你就可以做这样的事情。
Python
1 2 3 4 5
| def adder(x):
return lambda y: x + y
add5 = adder(5)
add5(1)
6 |
从python的片段中可以看到,函数adder接受一个参数x,并返回一个匿名函数或lambda,它接受另一个参数y。该匿名函数允许您从函数创建函数。这是一个简单的例子,但它应该传递lambda和闭包所具有的强大功能。
其他语言示例
Perl 5
1 2 3 4 5 6 7 8 9 10 11 12
| sub adder {
my ($x) = @_;
return sub {
my ($y) = @_;
$x + $y
}
}
my $add5 = adder(5);
print &$add5(1) == 6 ?"ok
" :"not ok
"; |
JavaScript
1 2 3 4 5 6 7
| var adder = function (x) {
return function (y) {
return x + y;
};
};
add5 = adder(5);
add5(1) == 6 |
JavaScript(ES6)
1 2 3
| const adder = x => y => x + y;
add5 = adder(5);
add5(1) == 6 |
方案
1 2 3 4 5 6 7 8
| (define adder
(lambda (x)
(lambda (y)
(+ x y))))
(define add5
(adder 5))
(add5 1)
6 |
C 3.5或更高
1 2 3 4 5 6 7 8 9 10 11 12
| 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); |
迅捷
1 2 3 4 5 6
| func adder(x: Int) -> (Int) -> Int{
return { y in x + y }
}
let add5 = adder(5)
add5(1)
6 |
PHP
1 2 3 4 5 6 7 8
| $a = 1;
$b = 2;
$lambda = function () use (&$a, &$b) {
echo $a + $b;
};
echo $lambda(); |
哈斯克尔
Java看到这个帖子
1 2 3 4 5 6
| // 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 |
卢阿
1 2 3 4 5 6 7
| adder = function(x)
return function(y)
return x + y
end
end
add5 = adder(5)
add5(1) == 6 -- true |
科特林
1 2
| val pred = { x: Int -> x % 2 == 0 }
val result = pred(4) // true |
红宝石
Ruby略有不同,因为您不能使用与调用函数完全相同的语法来调用lambda,但它仍然有lambda。
1 2 3 4 5
| def adder(x)
lambda { |y| x + y }
end
add5 = adder(5)
add5[1] == 6 |
Ruby是Ruby,有一个lambdas的缩写,所以您可以这样定义adder:
1 2 3
| def adder(x)
-> y { x + y }
end |
lambda是内联定义的函数类型。除了lambda之外,通常还具有某种类型的变量,可以保存对函数、lambda或其他类型的引用。
例如,这里有一段不使用lambda的C代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| 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);
} |
这调用计算器,不仅传递两个数字,而且调用计算器内部的哪个方法来获得计算结果。
在C 2.0中,我们使用匿名方法,将上述代码缩短为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| 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中,我们得到了lambda,这使得代码更短:
1 2 3 4 5 6 7 8 9 10 11 12
| 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);
} |
它指的是lambda微积分,它是一个只有lambda表达式的形式系统,它表示一个函数,它接受一个函数作为它的唯一参数并返回一个函数。lambda演算中的所有函数都是这种类型,即λ : λ → λ。
Lisp使用lambda概念命名其匿名函数文本。此lambda表示一个函数,该函数接受两个参数x和y,并返回其乘积:
它可以这样在线应用(评估值为50):
1
| ((lambda (x y) (* x y)) 5 10) |
名称"lambda"只是一个历史产物。我们所说的是一个表达式,它的值是一个函数。
一个简单的例子(将scala用于下一行)是:
1
| args.foreach(arg => println(arg)) |
其中,foreach方法的参数是匿名函数的表达式。上面这一行或多或少与编写类似的代码相同(不是很真实的代码,但您会明白这一点):
1 2 3 4 5
| void printThat(Object that) {
println(that)
}
...
args.foreach(printThat) |
除此之外,您不必费心:
在其他地方声明函数(并在稍后重新访问代码时查找它)。
命名你只使用过一次的东西。
一旦习惯了对值进行函数运算,没有这些值就好像被要求命名每个表达式一样愚蠢,比如:
1 2 3
| int tempVar = 2 * a + b
...
println(tempVar) |
而不仅仅是在需要的地方编写表达式:
确切的符号因语言而异;并不总是需要希腊语!;-)
lambda演算是一个一致的数学替换理论。在学校数学中,我们可以看到例如x+y=5与x?y=1配对。除了处理单个方程的方法外,还可以将这两个方程中的信息放在一起,前提是要逻辑地进行跨方程替换。lambda演算编码了正确的替换方法。
考虑到y = x?1是第二个方程的有效重排,这个:λ y = x?1表示用符号x?1代替符号y的函数。现在假设把λ y应用到第一个方程中的每个项。如果一个术语是y,则执行替换;否则不执行任何操作。如果你在纸上这样做,你会看到应用λ y将如何使第一个方程可解。
这是一个没有任何计算机科学或编程的答案。
我能想到的最简单的编程示例来自http://en.wikipedia.org/wiki/joy_u(编程语言)它是如何工作的:
here is how the square function might be defined in an imperative
programming language (C):
1 2 3 4
| int square(int x)
{
return x * x;
} |
The variable x is a formal parameter which is replaced by the actual
value to be squared when the function is called. In a functional
language (Scheme) the same function would be defined:
1 2 3
| (define square
(lambda (x)
(* x x))) |
This is different in many ways, but it still uses the formal parameter
x in the same way.
添加:http://imgur.com/a/xbhub

稍微过于简单:lambda函数可以传递给其他函数,并且可以访问它的逻辑。
在C lambda中,语法通常以与匿名委托相同的方式编译为简单方法,但它也可以分解并读取逻辑。
例如(在c 3中):
1 2
| LinqToSqlContext.Where(
row => row.FieldName > 15 ); |
LinqToSQL可以读取该函数(x>15),并将其转换为实际的SQL,以便使用表达式树执行。
上述声明为:
1 2
| select ... from [tablename]
where [FieldName] > 15 --this line was 'read' from the lambda function |
这与普通方法或匿名委托(实际上只是编译器的魔力)不同,因为它们不能被读取。
并非所有使用lambda语法的c中的方法都可以编译为表达式树(即实际lambda函数)。例如:
1 2
| LinqToSqlContext.Where(
row => SomeComplexCheck( row.FieldName ) ); |
现在无法读取表达式树-SomeComplexCheck无法分解。SQL语句将不使用WHERE执行,数据中的每一行都将通过SomeComplexCheck。
lambda函数不应与匿名方法混淆。例如:
1 2 3 4
| LinqToSqlContext.Where(
delegate ( DataRow row ) {
return row.FieldName > 15;
} ); |
这也有一个"inline"函数,但这一次它只是编译器的魔力——C编译器将把它拆分成一个新的实例方法,并使用一个自动生成的名称。
无法读取匿名方法,因此无法像对lambda函数那样转换逻辑。
我喜欢本文中关于lambdas的解释:linq的演变及其对c设计的影响。这对我来说很有意义,因为它为兰姆达斯展示了一个真实的世界,并将其作为一个实际的例子加以构建。
他们的快速解释:lambda是一种将代码(函数)视为数据的方法。
Ruby中lambda的示例如下:
1 2 3 4 5 6
| hello = lambda do
puts('Hello')
puts('I am inside a proc')
end
hello.call |
将生成以下输出:
1 2
| Hello
I am inside a proc |
这个问题得到了正式的回答,所以我不会再多加一点。
对于一个对数学或编程知之甚少或一无所知的人来说,我用一个非常简单的非正式词汇,把它解释为一个小的"机器"或"盒子",它接受一些输入,做一些工作,产生一些输出,没有特定的名称,但我们知道它在哪里,仅凭这个知识,我们就使用它。
实际上,对于一个知道函数是什么的人,我会告诉他们,它是一个没有名字的函数,通常放在内存中的一个点上,可以通过引用该内存来使用(通常通过变量的使用-如果他们听说过函数指针的概念,我会把它们作为类似的概念使用)。-这个答案涵盖了相当基础的内容(没有提到闭包等),但是我们可以很容易地理解这一点。
@布莱恩,我一直在用C,LINQ和非LINQ操作符。例子:
1 2 3
| string[] GetCustomerNames(IEnumerable<Customer> customers)
{ return customers.Select(c=>c.Name);
} |
在c之前,我在javascript中使用匿名函数回调Ajax函数,甚至在术语Ajax出现之前:
1
| getXmlFromServer(function(result) {/*success*/}, function(error){/*fail*/}); |
不过,C的lambda语法的有趣之处在于,它们本身的类型无法推断(即,您不能键入var foo=(x,y)=>x*y),但根据它们被分配到的类型,它们将被编译为表示表达式的委托或抽象语法树(这就是Linq对象映射器如何进行"语言集成"的方式)。"魔法"。
Lisp中的lambda也可以传递给报价运算符,然后作为列表列表进行遍历。一些强大的宏是这样生成的。
你可以把它看作一个匿名函数-这里有更多的信息:维基百科-匿名函数
只是因为我看不到这里的C++ 11例子,所以我会在这里发布这个好的例子。在搜索之后,它是我能找到的最清晰的语言特定的例子。
你好,兰姆达斯,版本1
1 2 3 4 5 6 7 8 9
| template<typename F>
void Eval( const F& f ) {
f();
}
void foo() {
Eval( []{ printf("Hello, Lambdas
"); } );
} |
你好,兰姆达斯,第2版:
1 2 3 4 5
| void bar() {
auto f = []{ printf("Hello, Lambdas
"); };
f();
} |
我很难用lambda表达式来表达自己的想法,因为我在VisualFoxPro中工作,它有宏替换和execscript和evaluate()函数,它们的作用似乎大致相同。
1 2 3 4 5
| ? Calculator(10, 23,"a + b")
? Calculator(10, 23,"a - b");
FUNCTION Calculator(a, b, op)
RETURN Evaluate(op) |
使用正式lambda的一个明显的好处是(我假设)编译时检查:在试图运行文本字符串之前,Fox不会知道您是否输入了上面的文本字符串。
这对于数据驱动的代码也很有用:您可以将整个例程存储在数据库的备注字段中,然后在运行时对它们进行评估。这允许您调整应用程序的一部分,而实际上不需要访问源。(但这完全是另一个话题。)
For a person without a comp-sci background, what is a lambda in the world of Computer Science?
我将用简单易读的python代码一步一步地直观地演示它。
简而言之,lambda只是一个匿名的内联函数。
让我们从作业开始,以基础算术为背景,了解一个大一新生的lambdas。
分配蓝图为"名称=值",请参见:
1 2 3 4 5 6
| In [1]: x = 1
...: y = 'value'
In [2]: x
Out[2]: 1
In [3]: y
Out[3]: 'value' |
"x"、"y"是名称,"1"是值。试一试数学中的函数
1 2
| In [4]: m = n**2 + 2*n + 1
NameError: name 'n' is not defined |
错误报告,不能将数学直接写为代码,"n"应该被定义或赋值。
1 2 3 4
| In [8]: n = 3.14
In [9]: m = n**2 + 2*n + 1
In [10]: m
Out[10]: 17.1396 |
它现在起作用了,如果你坚持把两条分离线组合成一条呢?有人来了。
1 2 3
| In [13]: j = lambda i: i**2 + 2*i + 1
In [14]: j
Out[14]: <function __main__.<lambda>> |
未报告错误。
这是对lambda的一瞥,它使您能够在一行中编写一个函数,就像在数学中一样,直接在计算机中编写函数。
我们稍后再看。
让我们继续深入研究"作业"。
如上图所示,等号=适用于简单数据(1和‘value’)类型和简单表达式(n**2+2*n+1)。
试试这个:
1 2 3 4 5
| 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文档
复合语句怎么样?
1 2 3 4 5
| 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使其工作
1 2 3 4 5 6
| In [23]: def m(n):
...: if n > 0:
...: return n**2 + 2*n + 1
...:
In [24]: m(2)
Out[24]: 9 |
tada,分析一下,"m"是名称,"n*2+2*n+1"是值。:是"="的变体。找到它,如果只是为了理解,一切都从任务开始,一切都是任务。
现在返回到lambda,我们有一个名为'm'的函数
尝试:
1 2 3
| In [28]: m = m(3)
In [29]: m
Out[29]: 16 |
这里有两个名称"m",函数m已经有一个名称,重复。
它的格式如下:
1 2 3 4
| 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,它使您能够像数学中一样,在一条直线上编写函数。
lambda是匿名的
希望,这有帮助。
在cs的上下文中,lambda函数是一个抽象的数学概念,它解决了数学表达式的符号评估问题。在这种情况下,lambda函数与lambda项相同。
但是在编程语言中,它是不同的。这是一段被宣布为"到位"的代码,可以作为"一流公民"传递。这个概念似乎很有用,所以它几乎可以应用到所有流行的现代编程语言中(参见lambda函数everwhere post)。
它是一个没有名称的函数。例如,在C中,您可以使用
1
| numberCollection.GetMatchingItems<int>(number => number > 5); |
返回大于5的数字。
这里是lambda部分吗?它表示一个接受参数(数字)并返回布尔值(数字>5)的函数。GetMatchingItems方法对集合中的所有项使用此lambda,并返回匹配项。
例如,在JavaScript中,函数被视为与其他所有函数相同的混合类型(int、string、float、bool。因此,您可以在运行中创建函数,将它们分配给事物,并在以后调用它们。它很有用,但是,不是你想过度使用的东西,或者你会混淆所有在你之后必须维护你的代码的人…
这是我正在玩的代码,看兔子洞有多深:
1 2 3 4 5 6 7 8
| 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]()()(); |
A Lambda Function, or a Small Anonymous Function, is a self-contained block of functionality that can be passed around and used in your code. Lambda has different names in different programming languages – Lambda in Python and Kotlin, Closure in Swift, or Block in C and Objective-C. Although lambda's meaning is quite similar for these languages it has slight distinctions sometimes.
让我们看看lambda(closure)如何在swift 4.2中使用sorted()方法工作——从普通函数到最短表达式:
1
| let coffee: [String] = ["Cappuccino","Espresso","Latte","Ristretto"] |
1。正规函数
1 2 3 4 5 6 7
| func backward(_ n1: String, _ n2: String) -> Bool {
return n1 > n2
}
var reverseOrder = coffee.sorted(by: backward)
// RESULT: ["Ristretto","Latte","Espresso","Cappuccino"] |
2。闭包表达式
1 2 3
| reverseOrder = coffee.sorted(by: { (n1: String, n2: String) -> Bool in
return n1 > n2
}) |
三。内联闭包表达式
1
| reverseOrder = coffee.sorted(by: { (n1: String, n2: String) -> Bool in return n1 > n2 } ) |
4。从上下文推断类型
1
| reverseOrder = coffee.sorted(by: { n1, n2 in return n1 > n2 } ) |
5。从单个表达式闭包隐式返回
1
| reverseOrder = coffee.sorted(by: { n1, n2 in n1 > n2 } ) |
6。速记参数名称
1 2 3
| reverseOrder = coffee.sorted(by: { $0 > $1 } )
// $0 and $1 are closure’s first and second String arguments. |
7。操作员方法
1 2 3
| reverseOrder = coffee.sorted(by: >)
// RESULT: ["Ristretto","Latte","Espresso","Cappuccino"] |
希望这有帮助。
我也明白了。我在JS上用过这个:
1 2 3 4 5 6 7
| var addAndMult = function(x) {
return (function(y) {
return (function(z) {
return (x+y)*z;
});
});
}; |
它增加2到4,然后将结果乘以6。但是我发现有时很难阅读:(
我还做了一个有趣的foreach函数:
1 2 3 4 5 6 7
| 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);
这个方法将迭代一个数组并执行一个操作——在这种情况下,打印到控制台。现在我也明白了为什么拉姆达是强大的。
在计算机编程中,lambda是一段代码(语句、表达式或它们的一组),它从外部源获取一些参数。它不能总是一个匿名函数——我们有很多方法来实现它们。
我们在表达式、语句和函数之间有明确的分离,这是数学家没有的。
编程中的"函数"一词也不同——我们有"函数是一系列要做的步骤"(从拉丁语"perform")。在数学中,它是关于变量之间的相关性。
函数语言试图尽可能地与数学公式相似,它们的单词含义几乎相同。但是在其他编程语言中,我们有不同的语言。
这个问题已经被完全回答了,我不想再详细讨论。我想分享一下在Rust中编写数值计算时的用法。
有一个lambda(匿名函数)示例
1 2
| 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"。
输出如下
1 2 3
| println!("f={:.6} df={:.6}", f(10.0), df(10.0))
f=98.000000 df=20.000000 |
想象一下,你有一家有送货选择的餐厅,你有一份订单需要在30分钟内完成。关键是客户通常不在乎你是骑自行车送食物还是赤脚送食物,只要你保持食物的温暖和捆绑。因此,让我们将这个习语转换为具有匿名和定义的传输函数的javascript。
下面我们定义了我们传递aka的方式,我们定义了一个函数的名称:
1 2 3 4
| // ES5
var food = function withBike(kebap, coke) {
return (kebap + coke);
}; |
如果我们使用arrow/lambda函数来完成这个传输,会怎么样?
1 2
| // ES6
const food = (kebap, coke) => { return kebap + coke }; |
你看,对客户来说没有区别,也没有浪费时间去思考如何发送食物。就寄吧。
顺便说一句,我不推荐带可乐的kebap,这就是为什么上面的代码会给你带来错误。玩得高兴。