为什么某些功能语言需要软件事务存储?


24

根据定义,功能语言不应保留状态变量。那么,为什么Haskell,Clojure和其他公司提供软件事务存储(STM)实现?两种方法之间有冲突吗?


我只想链接这篇有趣的论文,说明很多。
猎鹰

1
需要明确的是,所有功能语言都保持状态,但是纯度要求变量一旦设置就不会改变。
罗伯特·哈维

Answers:


13

保持可变状态的功能语言没有错。甚至“纯”功能语言(例如Haskell)也需要保持状态才能与现实世界进行交互。Clojure之类的“不纯正”功能语言会产生副作用,其中包括变异状态。

要点是,除非您确实需要,否则功能语言会阻止可变状态。一般样式是使用纯函数和不可变数据进行编程,并且仅在需要代码的特定部分中与“不纯”可变状态进行交互。这样,您可以将其余代码库保持为“纯”。

我认为STM在功能语言中更常见的原因有很多:

  • 研究:STM是一个热门研究主题,编程语言研究人员通常更喜欢使用功能语言(本身是一个重新研究主题,而且更容易创建有关程序行为的“证明”)
  • 锁不构成:STM可以看作是基于锁的并发方法的替代方法,当您通过组合不同的组件扩展到复杂的系统时,它将开始出现问题。可以说这是STM的主要“务实”原因
  • STM非常适合不变性:如果您有一个大的不可变结构,则要确保它保持不变,因此您不希望其他线程进入并使某些子元素发生突变。同样,如果可以保证所述数据结构的不变性,则可以可靠地将其视为STM系统中的稳定“值”。

我个人喜欢Clojure允许可变性的方法,但仅在可能参与STM交易的严格控制“托管引用”的情况下。语言中的其他所有内容都是“纯功能性的”。

  ;; define two accounts as managed references
  (def account-a (ref 100))
  (def account-b (ref 100))

  ;; define a transactional "transfer" function
  (defn transfer [ref-1 ref-2 amount]
    (dosync
      (if (>= @ref-1 amount)
        (do 
          (alter ref-1 - amount)
          (alter ref-2 + amount))
        (throw (Error. "Insufficient balance!")))))

  ;; make a stranfer
  (transfer account-a account-b 75)

  ;; inspect the accounts
  @account-a
  => 25

  @account-b
  => 175

请注意,上面的代码是完全事务性的和原子的-读取另一个事务中的两个余额的外部观察者将始终看到一致的原子状态,即两个余额总和为200。对于基于锁的并发来说,这是一个令人惊讶的难题在具有许多交易实体的大型复杂系统中解决。

对于某些其他启发,​​Rich Hickey 在本视频中出色地解释了Clojure的STM


3

根据定义,功能语言不应保留状态变量

您的定义是错误的。无法使用无法维持状态的语言。

功能性和命令性语言之间的区别不是它们中的一种具有状态而另一种则没有。这是他们维持状态的一种方式。

命令式语言的状态遍及整个程序。

功能语言通过类型签名显式隔离和维护状态。这就是它们提供诸如STM之类的复杂状态管理机制的原因。


2

有时程序需要可变的状态(例如,Web应用程序的数据库内容),并且能够在不失去功能编程优势的情况下使用它是很好的。在非功能语言中,可变状态会渗透到一切。如果您使用某种特殊的API对其进行了明确说明,则可以将其限制在一个小的可识别区域中,而其他所有内容都只能发挥功能。FP的优点包括调试方便,可重复的单元测试,轻松的并发性以及多核/ GPU友好性。


您可能是指可变状态。 所有程序都保持状态,即使是功能程序也是如此。
罗伯特·哈维

你是对的。显然,我没有花足够的时间进行函数式编程,以致错过了这一点。
将于
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.