每个人都在谈论这个'Lambda'是什么?

时间:2009-07-06 07:58:49

标签: lambda

每个人都在谈论这个'Lambda'是什么?很多人似乎都喜欢它,但我可以从中收集的只是将一大堆代码填入单个表达式的方式。

有人可以告诉我它的真正价值吗?

14 个答案:

答案 0 :(得分:177)

无名称的功能

简单地说,lambda是一个没有名字的函数,或者是一个匿名函数。一小段可执行代码,可以传递,就像它是一个变量一样。在JavaScript中:

function () {}; // very simple

现在让我们看看这些lambdas的一些用途。

摘要样板代码

Lambdas可用于抽象样板代码。例如循环。我们习惯整天写forwhile个循环。但这是不编写的代码。我们可以在循环中提取代码,这是循环中最重要的部分,并抽象出其余部分:

for (var i=0; i<array.length; i++) {
    // do what something useful with array[i]
}

使用forEach数组对象,变为:

array.forEach(function (element, index) {
   // do something useful with element
   // element is the equivalent of array[i] from above
});

上面的抽象可能没那么有用,但还有其他更高阶的函数,比如forEach,它们可以执行更多有用的任务。例如filter

var numbers = [1, 2, 3, 4];
var even    = [];

// keep all even numbers from above array
for (var i=0; i<numbers.length; i++) {
    if (numbers[i] % 2 === 0) {
        even.push(numbers[i]);
    }
}

alert(even);

// Using the filter method
even = [1, 2, 3, 4].filter(function (number) {
    return number % 2 === 0;
});

alert(even);

代码执行延迟

在某些可以使用事件概念的环境中,我们可以使用lambdas来响应某些时间点可能发生的事件。

window.onload = function () {
    alert("Loaded");
};

window.setTimeout(function () {
    alert("Code executed after 2 seconds.");
}, 2000);

这可以通过其他方式完成,但这些方法相当冗长。例如,在Java中有Runnable接口。

职能工厂

在此之前,我们大多只使用lambdas来表达其语法糖能力。但有些情况下,lambdas可能更有用。例如,我们可能有返回lambdas的函数。假设我们有一个函数,我们希望它的返回值被缓存。

var users = [];
var getUser = function (name) {
    if (! users[name]) {
        // expensive operations to get a user. Ajax for example
        users[name] = user_from_ajax;
    }

    return users[name];
};

稍后,我们可能会注意到我们有类似的功能:

var photos = [];
var getPhoto = function (name) {
    if (! photo[name]) {
        // expensive operations to get a user. Ajax for example
        photos[name] = photo_from_ajax;
    }

    return photos[name];
};

那里有明显的模式,所以让我们把它抽象出来。我们使用memoization

/**
 * @param {Array}     store Data structure in which we cache lambda's return values
 * @param {Function}  lambda
 * @return {Function} A function that caches the result of calling the lambda param
 */
var memoize = function (store, lambda) {
    // return a new lambda
    return function (name) {
        if (! store[name]) {
            // Execute the lambda and cache the result
            store[name] = lambda(name);
        }

        return store[name];
    };
};

var getUsers = memoize([], function (name) {
    // expensive operations to get a user. Ajax for example
});

var getPhotos = memoize([], function (name) {
    // expensive operations to get a photo. Ajax for example
});

正如您所看到的,通过使用lambdas,我们能够抽象出缓存/存储逻辑。如果对于另一个例子有一些解决方法,我相信使用其他技术很难解决这个特殊问题。我们设法将一些重要的样板代码提取到一个地方。更不用说我们摆脱了usersphotos个全局变量。

查看您的个人资料,我发现您主要是Python用户。对于上述模式,Python具有装饰器的概念。有很多example on the net for memoization装饰器。唯一的区别是在Python中你最有可能在装饰器函数中有一个命名的嵌套函数。原因是Python只支持单表达式lambdas。但这个概念是一样的。

作为Python lambda使用的一个例子。我们过滤偶数的上述代码可以用Python表示:

filter(lambda x: x % 2 == 0, [1, 2, 3, 4])

无论如何,如果没有封闭,lambdas就不那么强大了。闭包是使lambdas概念如此强大的原因。在我的memoization示例中,我使用闭包在store param周围创建了一个闭包。这样,即使在memoize函数返回其结果(lambda)之后,我也可以访问该参数。

答案 1 :(得分:19)

术语“lambda”用于表示匿名函数,通常为closure。它们很有用,因为它们允许您编写使用其他函数的函数,而不会不必要地膨胀您的代码。例如,在Ruby中:

(1..100).select {|num| num % 2 == 0}

这将创建一个包含1到100之间偶数的数组。我们不必编写显式循环 - select方法接受一个用于测试值的函数,所以我们需要的只是我们的自定义逻辑。这使我们可以在几乎没有任何努力或开销的情况下大大地定制方法。基本上,我们可以用较小的函数组合函数。

这只是他们能做的一个简单的例子。将函数作为数据传递的能力非常强大,函数式语言程序员通常会用它来做一些非常棒的事情。

答案 2 :(得分:6)

“Lambda”可能只是太少了。看看Lambda calculus。 它在函数式编程中很有用。

函数式编程是另一种编程范式(如过程式或面向对象)。

答案 3 :(得分:5)

.NET中的Lambdas通常被称为“语法糖”。它们不直接影响功能,但是它们使语言更易于人们使用。

当你明白使用它们的力量时,我相信你会发现与使用委托/匿名方法的旧式方式相比,你将编写更少的代码。

答案 4 :(得分:2)

Dr Dobbs Journal有一个有用的article introducing lambda expressions(在C ++的上下文中,但我认为你可以将原则应用于任何语言)。

正如文章所说:“lambda表达式是一个高度紧凑的表达式,不需要单独的类/函数定义。”

因此,使用清单1和1的示例来自DDJ的2而非写作:

std::for_each( vec.begin(), vec.end(), print_to_stream<std::string>(std::cout));

这需要一个单独的类定义,如:

template <typename T, typename Stream> class print_to_stream_t {
  Stream& stream_;
public:
  print_to_stream_t(Stream& s):stream_(s) {}
  void operator()(const T& t) const {
    stream_ << t;
  }
};
template <typename T,typename Stream> 
print_to_stream_t<T,Stream>   print_to_stream(Stream& s) {
  return print_to_stream_t<T,Stream>(s);
}

使用Boost lambda library可以成为:

std::for_each(vec.begin(),vec.end(),std::cout << _1);

使内容保持内联。

The article还解释了lambda表达式的一些更多应用。

我认为the DDJ article中的一个关键点是“通常,在调用站点需要小而且不需要过于复杂的函数时使用lambda表达式。如果函数不重要,则不需要lambda表达式但是正常的功能或功能对象。“

答案 5 :(得分:2)

如果您曾经使用过使用函数指针,委托,策略或观察者模式/事件处理的函数/方法,并且想到自己“我正在编写整个函数只是为了使用它一次 - 传递它这个方法;我希望我能把它写到位,而不是混乱我的代码“ - 这就是你可能使用Lambda函数的地方。支持此构造的语言通常也会大量利用将函数作为参数传递的概念,特别是在处理列表(第一类函数和高阶函数)方面。对于函数式语言尤其如此,它们依赖于函数组合而不是内存修改来进行计算。在某些情况下(在Python等语言中),使用带有列表推导的lambda函数也被认为比等效的foreach循环更具可读性。

答案 6 :(得分:2)

'lambda'qua word是计算机科学类型可能在数学或逻辑方面接受培训而不是计算机科学学位的术语。他们中的一些人制定了一种称为“函数式编程”的范例,与命令式完全不同,也非常强大。 AFAIK这是该术语开始使用的环境。

数学家和逻辑学家使用奇怪的词语。

'lambda'听起来真的很深奥 - 好像它们是一种非常奇怪和特殊的东西。实际上,如果您为Web浏览器应用程序编写JavaScript并使用“var foo = function(){...}”惯用法,那么您一直在使用lambda函数。

答案 7 :(得分:1)

lambda表达式是一种简单的函数形式。这个想法是左边的某种形式(相当于参数)变成了右边的形式(相当于身体)。

例如,在c sharp:

x => x * x

是一个将值设为平方的lambda。形式的东西

x

成为

的形式
x * x

答案 8 :(得分:0)

“lambda表达式是一个匿名函数,可以包含表达式和语句,可用于创建委托或表达式树类型。

所有lambda表达式都使用lambda operator =&gt;,它被读作“转到”。 lambda运算符的左侧指定输入参数(如果有),右侧包含表达式或语句块。 lambda表达式x =&gt; x * x读作“x转到x乘x。”

来自MSDN

答案 9 :(得分:0)

你可以在这里找到你需要知道的所有事情(关于C#Lambdas):
Lambda expressions

答案 10 :(得分:0)

有关Lambda表达式的完整说明,请查看Wikipedia。 (向下滚动到 Lambda演算和编程语言部分。)Lambda表达式不是新的,它们不仅仅是C#的一部分,而是80年前引入计算的东西! Lambda表达式是函数式编程的基础。

它有价值吗?好吧,考虑到它实际上很老了,我会说:对于任何进行计算的人都非常有价值。

答案 11 :(得分:0)

如果你是Java,你在过去几个月里已经听过很多关于lambdas或者闭包的内容,因为在Java 7中添加这个功能有不同的建议。但是,我认为comitee放弃了它。其中一项建议来自Neal Gafter,并在此详细解释:javac.info。这有助于我理解用例和优势(尤其是内部类)

答案 12 :(得分:0)

对于java lambdas,这可能是一个很好的起点:

http://rodrigouchoa.wordpress.com/2014/09/10/java-8-lambda-expressions-tutorial/

答案 13 :(得分:-1)

是的,这只是将大量代码行填充到单个表达式中的一种方式。但是,如此高效的填空,它可以为您的程序提供一些新的方法。

通常人们会避免编写委托或回调并恢复到程序样式,因为为单个表达式声明新函数或类太多了。

Lambda表达式使得即使对于最小的任务也使用回调是值得的,这可能使代码更清晰。可能不会。