需要闭包或lambda的示例

需要闭包或lambda的示例,lambda,closures,computer-science,terminology,Lambda,Closures,Computer Science,Terminology,我花了一个小时阅读了很多关于lambdas和closures的帖子。我想我理解它们是什么,即它们是如何工作的,但我不理解它们存在的原因。我看到的许多例子模糊地提到了它们的“力量”,但在每一个例子中,我都能想到一种更简单的方法来完成所演示的内容。也许这是因为示例故意过于简单(为了便于理解),或者我太过密集。但我真正想看到的是一个清晰的例子,说明你可以通过闭包或lambda来完成一些没有闭包或lambda就无法完成的事情。也许这是一个复杂的问题,因为所有的编程范例最终都归结为相同的机器指令,而任何可

我花了一个小时阅读了很多关于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#

假设您有一个需要值的函数。但该值的计算成本很高,因此要求如下:

  • 如果函数不需要该值,则根本不应对其进行评估
  • 如果函数多次需要该值,则只需对其进行一次评估
Lambda表达式使这非常容易,因为您可以使用捕获的变量“缓存”计算值:

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表达式可以让编译器自动执行
  • 您必须为每种类型的操作编写单独的接口

Lambda演算实际上非常简单,而且本身没有那么大的用处。然而,当您开始学习lambda演算的含义和使用函数设计模式的应用程序控制策略时,您将成为一名更好、更强大的程序员

前提是函数也是值,这使得它对于抽象许多概念非常强大。您的两个示例展示了实现闭包和curry的最简单方法。这些都是微不足道的例子。当您开始使用函数式编程时,这些模式将作为非常强大的方式一次又一次地抽象出复杂性

关注点分离 当您开始使用高阶函数进行抽象时,函数式编程非常有用,典型的例子是-我想对对象集合做些什么

因此,在命令式程序中,使用for循环:

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!