函数式编程中应避免赋值,但在 clojure 中我们经常使用
let
。
let
只是一种实用的方式还是赋值与使用let
不同?我们不应该避免函数式编程中的赋值吗?
可变状态通常违背函数式编程的核心概念。
但是,
let
仅仅将名称绑定到值。如果该值是不可变的,那么它就没有理由与函数式编程理想不一致。
def
表达式是一个赋值,也是一个
let
表达式。为事物和过程/函数命名是一种抽象手段 - 编程意味着在重复出现的问题上应用抽象的很大一部分。命令式风格滥用分配进行突变,从而创建/维护/映射(全局)状态。如果没有赋值,变异是不可能的。 因此 FP 的目标是针对此类突变,而不是分配本身。
实际上 FP 本身并不是针对突变的。 即使在函数式语言中,在某些情况下出于性能原因也需要突变。
存在无害的突变 - 变量的突变无论如何都不会再在程序的其余部分中被引用 - 例如因为它们仅出现在特定范围内(例如,在
let
表达式或函数定义的范围内)。我倾向于称它们为“良性”突变。并且存在有害的突变——稍后提到的变量突变——在它们被创建的范围之外继续存在的变量突变——从而构成某种无限状态。我称它们为“恶性”突变。其实说FP完全避免状态也是错误的。
闭包实际上构成了 FP 中的状态。通过闭包,函数可以引用隐藏变量,这些变量在不同函数调用之间保留“内存”/状态。但它们的应用方式非常受控。
也许这就是定义 FP 如此困难的原因。人们很快就会过度简化某些事情,从而导致比澄清事情更多的混乱。