The*_*111 8 lambda computer-science closures terminology
我花了一个小时阅读这个网站上的很多帖子,其他人关于lambdas和closures.我想我明白它们是什么,即它们是如何工作的,但我不明白为什么它们存在.我看到的许多例子含糊地提到了他们的"权力",但在每一种情况下,我都能想到一种更简单的方法来完成所说明的内容.也许这是因为这些例子故意过于简单(为了便于理解),或者我可能很密集.但我真正喜欢的是看到一个明确的例子,说明你可以通过一个闭包或lambda完成的事情,如果没有一个你就无法实现.也许这是一个有问题的问题,因为所有编程范例最终归结为相同的机器指令,并且可以用一种语言完成的任何操作都可以在另一种语言中完成.所以我想我真正要问的是一个用闭包做的事情的例子比没有做的更优雅(对于我见过的任何例子似乎都不是这样).
这就是我所说的.
(define (make-counter)
(let ((count 0))
(lambda ()
(set! count (+ count 1))
count)))
(define x (make-counter))
(x) returns 1
(x) returns 2
...etc...
Run Code Online (Sandbox Code Playgroud)
我真的不知道Scheme,但我想我知道发生了什么.但是,这不是更直接并且完成同样的事情吗?伪代码:
function incrementCount(var counter) {
counter++;
return counter;
}
counter = 1;
counter = incrementCount(counter);
counter = incrementCount(counter);
Run Code Online (Sandbox Code Playgroud)
这是lambda上的另一个:什么是lambda(函数)?
给出的JavaScript示例:
var adder = function (x) {
return function (y) {
return x + y;
};
};
add5 = adder(5);
add5(1) == 6
Run Code Online (Sandbox Code Playgroud)
再说一次,为什么这样呢?为什么不说:
function adder(x, y) {
return x + y;
}
adder(5, 1);
Run Code Online (Sandbox Code Playgroud)
我看到的每个例子看起来都是一种过于复杂的方式来做一些可以用基本功能轻松完成的事情.这些例子当然没有说明我能看到的任何惊人的酷"力量".所以,请有人启发我,我一定是错过了什么.谢谢.
Lambda演算实际上非常简单,而且本身并没有那么有用.然而,当你开始学习lambda演算的含义和使用功能设计模式的应用程序控制策略时,你将成为一个更好,更强大的程序员.
前提是函数也是值,这使得抽象许多概念变得非常强大.您的两个示例显示了实现闭包和currying的最简单方法.这些都是微不足道的例子.当您开始使用功能样式进行编程时,这些模式将一次又一次地作为抽象复杂性的非常强大的方式出现.
函数式编程很有用,当你开始使用高阶函数进行抽象时,典型的例子是 - 我想对一组对象做一些事情.
所以在命令式程序中,你使用for循环:
result = Array(length);
for(i = 0; i < length; i++)
{
result[i] = dosomething(input[i]);
}
Run Code Online (Sandbox Code Playgroud)
请注意,在代码块中,dosomething函数正好在for循环的中间.你无法真正从实际的for-loop控制结构中分离出你对数组中每个元素所做的事情.
但是,通过使用函数样式,循环的控制结构使用map- 更高阶函数 - 被抽象掉- 您可以清楚地分离循环和函数应用这两个概念.这是方案中的等效代码.
(define result (map dosomething collection))
Run Code Online (Sandbox Code Playgroud)
map注意你正在遍历数组的每个元素.dosomething处理您正在对阵列的每个元素执行操作的事实.对此的推理变得更加清晰,并且更改代码变得更加容易.现在假设for您的代码中的每个循环都被此构造替换,它将保存多少行代码.
解决关闭和currying的概念.对象和函数之间存在等价关系.实质上,可以使函数看起来像行为一样.Javascript充分利用了这一事实.你可以用对象做任何事情,也可以用函数做.事实上,通过消除对象是什么和函数是什么之间的区别,你已经有效地整理了你的思想并且有一种思考问题的方法 - 也就是说,通过通过功能构建的代码.
我在这里使用clojure代码因为它是我很满意的:
这是琐碎加法器示例的clojure代码,使用加法器示例,您addn使用数字5 调用a 来获取向数字添加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]
Run Code Online (Sandbox Code Playgroud)
假设您有一个download-and-save-to带有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]
Run Code Online (Sandbox Code Playgroud)
请注意,即使您正在执行截然不同的事情,结构也是等效的.想想你将如何使用java或c ++解决这个问题.在类定义,工厂方法,类抽象,继承......中会涉及更多代码.你必须经历更多的仪式才能获得同样的效果.
由于您可以如此简洁地表达想法,函数式编程可以让您掌握许多难以用更冗长的语言表达的概念.您选择的工具将使探索某些问题更容易或更难.
我强烈推荐clojure - (http://www.4clojure.com/)和lighttable - (http://www.lighttable.com/,http://www.kickstarter.com/projects/ibdknox/light-table)开始.根据我的个人经验,我在一年的学习和探索clojure社区的概念类似于大约10年的学习java,c ++和python的结合.
哦,我有没有提到我学习所有这些东西有多么有趣?Monads,组合器,传播者,延续......当你有合适的工具来理解它们时,所有那些可怕的学术概念实际上都是触手可及的.