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