11

我试图了解功能语言的核心概念:

“函数式语言的一个核心概念是函数的结果取决于其输入,并且仅取决于其输入。没有副作用!”

http://www.haskell.org/haskellwiki/Why_Haskell_matters#Functions_and_side-effects_in_functional_languages

我的问题是,如果一个函数只在其本地环境中进行更改并返回结果,它如何与数据库或文件系统交互?根据定义,这不是访问实际上是全局变量或全局状态的东西吗?

用于解决或解决此问题的最常见模式是什么?

4

3 回答 3

12

仅仅因为函数式语言是函数式的(甚至可能像 Haskell 一样完全纯粹!),并不意味着用该语言编写的程序在运行时必须是纯粹的。

例如,在处理副作用时,Haskell 的方法可以很简单地解释:让整个程序本身是纯的(意味着函数总是为相同的参数返回相同的值并且没有任何副作用),但是让main函数的返回值是一个可以运行的动作。

试图用伪代码解释这一点,这里有一些用命令式非函数式语言编写的程序:

main:
  read contents of abc.txt into mystring
  write contents of mystring to def.txt

上面的main过程就是:描述如何执行一系列动作的一系列步骤。

将此与 Haskell 等纯函数式语言进行比较。在函数式语言中,一切都是表达式,包括主函数。因此,可以像这样阅读上述程序的等价物:

main = the reading of abc.txt into mystring followed by
       the writing of mystring to def.txt

因此,main是一个表达式,在评估时将返回一个操作,描述为了执行程序要做什么。这个动作的实际执行发生在程序员的世界之外。这就是它的工作原理;以下是可以编译和运行的实际 Haskell 程序:

main = readFile "abc.txt" >>= \ mystring ->
       writeFile "def.txt" mystring

a >>= b在这种情况下,可以说是“动作a后面跟着动作的结果ab,而运算符的结果是组合动作a和b。上面的程序当然不是惯用的 Haskell;可以将其重写如下(删除多余的变量):

main = readFile "abc.txt" >>=
       writeFile "def.txt"

...或者,使用语法糖和 do-notation:

main = do
  mystring <- readFile "abc.txt"
  writeFile "def.txt" mystring

上述所有程序不仅是等价的,而且就编译器而言它们是相同的。

这就是文件、数据库系统和 Web 服务器可以编写为纯函数程序的方式:通过程序将动作值线程化,以便将它们组合起来,最后在main函数中结束。这给了程序员对程序的巨大控制权,这也是为什么纯函数式编程语言在某些情况下如此吸引人的原因。

于 2011-12-06T21:32:22.110 回答
6

处理函数式语言中的副作用和杂质的最常见模式是:

  • 务实而不是纯粹主义者
  • 提供允许不纯代码和副作用的内置插件
  • 尽可能少地使用它们!

例子:

  • Lisp/方案: set!
  • Clojure:引用,并在 java 对象上使用变异方法
  • Scala:使用创建变量var
  • ML:不确定细节,但维基百科说它允许一些杂质

Haskell 有点作弊——它的解决方案是,对于访问文件系统或数据库的函数,当时整个宇宙的状态,包括 filesystem/db 的状态,将被传递给函数。 (1) 因此,如果你可以复制整个宇宙在那一刻的状态,那么你可以从这样的函数中得到两次相同的结果。当然,你不能在那个瞬间复制整个宇宙的状态,所以函数返回不同的值......

但是 Haskell 的解决方案,恕我直言,并不是最常见的。


(1)不确定这里的具体情况。感谢 CAMcCann 指出这个比喻被过度使用并且可能不是那么准确。

于 2011-12-06T22:00:25.130 回答
4

访问数据库与其他输入输出情况没有什么不同,例如print(17).

在热切评估的语言中,如 LISP 和 ML,有效编程的常用方法只是使用副作用,就像在大多数其他编程语言中一样。

在 Haskell 中,IO 问题的解决方案是使用 monads。例如,如果您检查HDBC,一个 haskell 数据库库,您可以看到那里的许多函数返回 IO 操作。

一些语言,如 Clean,使用唯一性类型来强制执行 Haskell 对 monad 所做的相同类型的顺序性,但如今这些语言更难找到。

于 2011-12-06T22:14:07.507 回答