我需要帮助了解我当前的OOP状态概念与在Haskell或Clojure等函数语言中完成的方式之间的区别.
使用一个陈腐的例子,假设我们正在处理简化的银行账户对象/结构/任何事情.在OOP语言中,我有一些类持有对BankAccount的引用,BankAccount将具有诸如利率之类的事件的实例变量,以及诸如setInterestRate()之类的方法,其改变对象的状态并且通常不返回任何内容.在说Clojure中,我有一个银行账户结构(一个美化的散列图),以及带有银行账户参数和其他信息的特殊函数,并返回一个新的结构.因此,我现在不再更改原始对象的状态,而是返回一个具有所需修改的新对象.
那么......我该怎么办呢?覆盖引用旧银行帐户的任何变量?如果是这样,那是否比改变状态的OOP方法有优势?最后,在这两种情况下,似乎有一个变量引用具有必要更改的对象.像我一样迟钝,我对发生的事情只有一个模糊的概念.
我希望这是有道理的,谢谢你的帮助!
在纯函数式中,您永远不会覆盖任何变量.
类比是物理学中的时空.如果你认为世界是3d,那么物体就没有固定的位置 - 它们随着时间的推移而移动.为了使数学对物理世界产生影响,我们因此添加时间维度并在特定时间考虑各种属性的值.在这样做的过程中,我们将研究对象变为常数.类似地,在编程中,通过使用不可变值有一个概念上的简单性.在现实世界中具有身份的对象可以被建模为一系列不可变值(对象在增加的时间的状态)而不是作为单个值的变化.
当然,如何将值序列与"对象标识"相关联的细节可能有点毛茸茸.Haskell有Monads可以让你模拟状态. 功能反应式编程是一种更为文字化的尝试,用纯粹的功能更新来模拟世界中的对象,我认为这是一个非常有前途的编程方向.
我会注意到,与Haskell不同,Clojure不是纯粹的,你可以按照你的建议更新变量.如果您只是在高级别更新一些变量,您仍然可能会享受函数式编程的许多概念简单优势.
据推测,在OO世界中,您有一个循环并且正在一次又一次地修改这些银行账户以响应请求.假设您有一整套帐户,这些帐户都有类型投资组合.然后在Haskell中你会编写一个纯函数
updatePortfolio :: Request -> Portfolio -> Portfolio
您的主循环可能会读取标准输入的请求,并使您的投资组合保持最新状态.(除非你能编写投资组合,否则这个例子并没有多大用处,但它更简单.)
readRequest :: IO Request -- an action that, when performed, reads a Request with side effects main :: Portfolio -> IO () -- a completely useless program that updates a Portfolio in response to a stream of Requests main portfolio = do req <- readRequest main (updatePortfolio req)
现在我希望你看到你的可变状态发生了什么:在一个典型的功能程序中,声明更改作为参数传递给函数.当状态改变时,你进行一个新的函数调用.调用处于尾部位置(你可以查找'正确的尾部调用'),因此它不使用任何额外的资源,事实上当编译器生成汇编代码时它会生成一个循环,它会保持指针指向寄存器中不断变化的投资组合.
这是一个非常玩具的例子,但我希望它能给你一些功能语言的味道.