需要闭包或lambda的示例
我花了一个小时阅读了很多关于lambdas和closures的帖子。我想我理解它们是什么,即它们是如何工作的,但我不理解它们存在的原因。我看到的许多例子模糊地提到了它们的“力量”,但在每一个例子中,我都能想到一种更简单的方法来完成所演示的内容。也许这是因为示例故意过于简单(为了便于理解),或者我太过密集。但我真正想看到的是一个清晰的例子,说明你可以通过闭包或lambda来完成一些没有闭包或lambda就无法完成的事情。也许这是一个复杂的问题,因为所有的编程范例最终都归结为相同的机器指令,而任何可以用一种语言完成的事情都可以用另一种语言完成。所以我想我真正想问的是一个例子,用闭包做的事情比不用闭包做的事情更优雅(这似乎不是我见过的任何例子的情况) 这就是我要说的 主要答案,方案中的一个示例:需要闭包或lambda的示例,lambda,closures,computer-science,terminology,Lambda,Closures,Computer Science,Terminology,我花了一个小时阅读了很多关于lambdas和closures的帖子。我想我理解它们是什么,即它们是如何工作的,但我不理解它们存在的原因。我看到的许多例子模糊地提到了它们的“力量”,但在每一个例子中,我都能想到一种更简单的方法来完成所演示的内容。也许这是因为示例故意过于简单(为了便于理解),或者我太过密集。但我真正想看到的是一个清晰的例子,说明你可以通过闭包或lambda来完成一些没有闭包或lambda就无法完成的事情。也许这是一个复杂的问题,因为所有的编程范例最终都归结为相同的机器指令,而任何可
(define (make-counter)
(let ((count 0))
(lambda ()
(set! count (+ count 1))
count)))
(define x (make-counter))
(x) returns 1
(x) returns 2
...etc...
我真的不知道这个计划,但我想我知道发生了什么。然而,这不是更简单,完成同样的事情吗?伪代码:
function incrementCount(var counter) {
counter++;
return counter;
}
counter = 1;
counter = incrementCount(counter);
counter = incrementCount(counter);
这是关于lambdas的另一个:
下面给出的JavaScript示例:
var adder = function (x) {
return function (y) {
return x + y;
};
};
add5 = adder(5);
add5(1) == 6
再说一遍,为什么要这样做?为什么不说:
function adder(x, y) {
return x + y;
}
adder(5, 1);
我看到的每一个例子似乎都是一种非常复杂的方法,可以用基本函数轻松完成一些事情。这些例子当然不能说明我所能看到的任何惊人的酷“力量”。所以,请有人告诉我,我一定错过了什么。谢谢。这个问题很难回答,因为你已经涵盖了所有的基础:你已经看到了示例、描述和解释——你甚至意识到lambda表达式可以编译成一种机器语言,而它本身并没有lambda表达式作为主要功能 尽管如此,我将尝试给出一个例子,这似乎是我个人使用lambda表达式的最常见的用例之一。我使用C#,这基本上是一种命令式语言,但具有lambda表达式作为内置功能,因此我的示例将使用C# 假设您有一个需要值的函数。但该值的计算成本很高,因此要求如下:
- 如果函数不需要该值,则根本不应对其进行评估
- 如果函数多次需要该值,则只需对其进行一次评估
bool computed = false;
MyType value = null;
var getValue = () => {
if (!computed)
{
value = computeValue(); // this is the expensive operation
computed = true;
}
return value;
};
现在我可以将getValue
传递到任何函数中,无论这个函数对它做了什么(即调用了多少次),我知道computeValue()
只会被调用一次
要在没有lambda的情况下执行相同的操作,我必须创建一个与此lambda闭包等效的类,并让它实现某种接口,例如:
sealed class Closure : IGetMyTypeValue
{
bool Computed = false;
MyType Value = null;
public Closure() { }
public MyType GetValue() // implements IGetMyTypeValue.GetValue()
{
if (!Computed)
{
Value = ComputeValue(); // this is the expensive operation
Computed = true;
}
return Value;
}
private MyType ComputeValue()
{
// expensive code goes here
}
}
[...]
var closure = new Closure();
// pass closure to a method that expects an IGetMyTypeValue
必须编写这个大型类的缺点是:
- 您必须为每一个这样昂贵的计算编写一个新类。这是非常重复的工作;使用lambda表达式可以让编译器自动执行
- 您必须为每种类型的操作编写单独的接口
result = Array(length);
for(i = 0; i < length; i++)
{
result[i] = dosomething(input[i]);
}
map
负责遍历数组的每个元素dosomething
负责对数组的每个元素执行操作。关于这一点的推理变得更加清晰,更改代码也变得更加容易。现在想象一下,代码中的每个for
循环都被这个构造替换了,它将保存多少行代码
廉价的建设者
解决闭包和咖喱的概念。对象和函数之间是等价的。从本质上讲,函数可以使其外观和行为类似于对象。Javascript充分利用了这一事实。可以对对象执行的任何操作,也可以对函数执行。事实上,通过消除对象和函数之间的区别,你已经有效地分离了你的思维,并且有了一种思考问题的方式——也就是说,通过功能构建的代码
我在这里使用clojure代码,因为这是我熟悉的:
这是用于普通加法器示例的clojure代码,在加法器示例中,您使用数字5调用一个addn
,以返回将5添加到数字的函数。一般用例可以是:
(defn addn [n] (fn [m] (+ m n))
(def add5 (addn 5))
(map add5 [1 2 3 4 5 6])
;; => [6 7 8 9 10 11]
假设您有一个函数下载并保存到
,该函数接受url和数据库,将url保存到数据库表,并在成功时返回true,您可以执行与+
完全相同的抽象:
(defn download-url-to [db]
(fn [url] (download-and-save-to url db)))
(def download-url-mydb (download-url-to mydb))
(map download-url-mydb [url1 url2 url3 url4 url5])
;; => [true true false true true]
请注意,即使您正在进行vastl,结构也是等效的
(defn download-url-to [db]
(fn [url] (download-and-save-to url db)))
(def download-url-mydb (download-url-to mydb))
(map download-url-mydb [url1 url2 url3 url4 url5])
;; => [true true false true true]
var MyClass = function(buttonId) {
var clickCounter = 0;
var myButton = document.getElementById(buttonId);
myButton.addEventListener(
'onclick',
function() {
clickCounter += 1;
});
};
var myButtonClickCounter = new MyClass();
// I define a class constructor that takes a string as an input parameter
var MyClass = function(buttonId) {
// I define a private member called click
var clickCounter = 0;
// I get the reference to the button with the given id.
var myButton = document.getElementById(buttonId);
// I attach to it a function that will be triggered when you click on it.
// The addEventListener method takes two arguments as input:
// - the name of the event
// - the function to be called when the event is triggered
myButton.addEventListener(
'onclick',
function() {
clickCounter += 1;
});
};
// I create an instance of MyClass for a button called myButton
var myButtonClickCounter = new MyClass('myButton');
var MyClass = function(buttonId) {
var clickCounter = 0;
var clickHandler = function() {
clickCounter += 1;
};
var myButton = document.getElementById(buttonId);
myButton.addEventListener(
'onclick',
clickHandler
);
};
var MyClass = function(buttonId) {
var clickCounter = 0;
var myButton = document.getElementById(buttonId);
myButton.addEventListener(
'onclick',
function() {
clickCounter += 1;
});
// This method takes a value x as input, and returns
// a boolean value, that tells you whether the button
// has been clicked more than the given x.
this.hasReached = function(x) {
return (clickCounter >= x);
};
};
// Somewhere else in your code...
var myButtonClickCounter = new MyClass('myButton');
...
if( myButtonClickCounter.hasReached(4) )
{
// Do some great stuff
}
function Ninja(){
var slices = 0;
this.getSlices = function(){
return slices;
};
this.slice = function(){
slices++;
};
}
var ninja = new Ninja();
ninja.slice();
console.log(ninja.getSlices()); // 1!
console.log(slices); // undefined!