在函数式编程中,闭包的位置
在函数式编程中,闭包的位置
我已经观看了罗伯特·马丁的演讲“函数式编程; 什么?为什么?何时?”\nhttps://www.youtube.com/watch?v=7Zlp9rKHGD4\n这次演讲的主要观点是,在函数式编程中,状态是不可接受的。\n马丁甚至进一步声称赋值是“邪恶”的。\n那么...考虑到这个演讲,我的问题是,在函数式编程中,闭包有何用处?\n当函数式代码中没有状态或变量时,创建和使用这样的闭包(不包含任何状态或变量的闭包)的主要原因是什么?闭包机制有用吗?\n没有状态或变量(也许只有不可变的标识符),就没有必要引用当前词法作用域(没有任何可以改变的东西)?\n在这种方法中,只需要使用类似Java的lambda机制就足够了,其中没有与当前词法作用域的链接(这就是为什么变量必须是final的原因)。\n在一些资料中,闭包被认为是函数式语言中必不可少的元素。
函数式编程中闭包的位置是什么? 这个问题的出现原因是函数式编程中需要处理局部状态的情况。解决方法是使用闭包来模拟静态变量或者使用局部可变变量。
闭包在函数式编程中的使用与在具有可变变量的语言中的使用类似,不同之处在于闭包(通常)不能被修改。闭包可以通过以下Clojure示例来说明这一点:
(let [a 10 f (fn [b] (+ a b))] (println (f 4))) ; 输出 "14"
在这种情况下,闭包的主要好处是我可以使用闭包来“部分应用”一个函数,然后传递部分应用的函数,而不需要传递未应用的函数和调用它所需的任何数据(在许多情况下非常有用)。在下面的示例中,如果我不想立即调用函数,我需要将变量 `a` 与函数一起传递,以便在调用 `f` 时可用。
但是,如果需要的话,还可以将一些可变性加入到闭包中(尽管,正如代码中指出的那样,这个示例是“邪恶的”):
(let [a (atom 10) ; Atoms 是可变的 f (fn [b] (do (swap! a inc) ; 增加 a (+ b)))] (println (f 4)) ; 输出 "15" (println (f 4))) ; 输出 "16"
这样可以模拟静态变量。您可以使用这种方法来做一些很酷的事情,比如定义 `memoize`。它使用“静态变量”来缓存引用透明函数的输入/输出。这会增加内存使用量,但如果使用正确,可以节省CPU时间。
我不同意反对拥有状态的观点。状态并不邪恶;它们是必要的。每个程序都有一个状态。全局的、可变的状态才是邪恶的。
还要注意,您可以在仍然以函数式方式编程的情况下具有可变性。假设我有一个包含对列表进行映射的函数。还假设,在映射过程中需要维护一个累加器。我有两个选择(忽略“手动操作”):
- 将 `map` 切换为 `fold`。
- 创建一个可变变量,并在映射过程中对其进行修改。
虽然应该优先选择第一种方法,但这两种方法在函数式编程中都可以使用。从“函数外部”的视角来看,即使一个版本在内部使用可变变量,也不会有任何区别。函数仍然可以是引用透明的和纯粹的,因为唯一受影响的可变状态局限于函数的局部,不可能对外部产生任何影响。
以下是一个使用局部可变变量进行修改的示例代码:
(defn mut-fn [xs] (let [a (atom 0)] (map (fn [x] (swap! a inc) ; 增加 a (+ x )) ; 将累加器设置为 x + a xs)))
请注意,变量 `a` 无法从函数外部看到,因此它产生的任何效果都无法引起全局变化。该函数对于每个输入都会产生相同的输出,因此它是有效纯的。
有人可能会争辩说,您的示例中的状态是邪恶的,因为函数 `f` 不再是引用透明的。
是的,模拟静态变量的方法是邪恶的。我只是想展示它可以在函数式语言中以一些可能的好处使用,但是,这远非是一个理想的用例。这就是为什么我添加了其他示例来表明局部可变状态也是有用而不会产生危害的。
在函数式编程中,闭包的位置是一个重要的问题。闭包的出现是因为函数式编程需要动态创建具有特定行为的新函数,以及对于局部变量的需求。
闭包是指函数可以访问其定义时所在的词法环境中的变量,即使函数在其定义时所在的作用域外被调用,闭包仍然可以访问这些变量。闭包可以实现对非可变数据的引用,因此在函数式编程中,闭包可以非常有用。
例如,考虑柯里化函数的例子:
add = \a -> \b -> a+b add1 = add(1) add3 = add(3) [add1(0), add1(2), add3(2), add3(5)] // [1, 2, 5, 8]
在这个例子中,内部的lambda函数闭包了变量a的值(或者闭包了变量a,由于不可变性,这没有区别)。
闭包并不是函数式编程的必要条件,就像局部变量也不是必要的条件一样。然而,闭包和局部变量都是非常好的想法。闭包允许以一种非常简单的方式表示函数式编程的最重要的任务:从抽象代码中动态创建具有特定行为的新函数。
总之,闭包在函数式编程中扮演着重要的角色。它们允许函数引用定义时所在的词法环境中的变量,使得函数可以具有动态行为。闭包的出现是为了满足函数式编程对于动态创建函数和对局部变量的需求。