2012-10-28 73 views
3

比方说,我们定义一个函数c sum(a, b)函数式编程风格,它返回它的参数的总和。到现在为止还挺好;所有FP的好东西没有任何问题。函数编程如何避免状态,当它似乎是不可避免的?

现在我们假设我们在一个具有动态类型和单态的有状态错误流的环境中运行它。那么假设我们传递的值为a和/或bsum未被设计为处理(即不是数字),并且它需要以某种方式指示错误。

但是如何?这个功能应该是纯粹的,无副作用的。它如何在全球错误流中插入错误而不违反该错误?

+2

这就是为什么通常纯功能和动态打字不能很好地结合在一起的原因。 –

+2

@JakubHampl是吗?即使在静态类型语言,你仍然必须运行时错误(如被零除),所以我不明白怎么会避免核心十二都在谈论这个问题(但无可否认我还没有完全理解这个问题) 。核心Xii:什么是错误流? – sepp2k

+0

@ sepp2k在这个问题的上下文中,“错误流”是一些报告错误的全局系统机制,比如std.err,异常等;通常是带外的,但不是必需的。 –

回答

9

没有编程语言,我知道有什么像内置的“单身状态错误流”,所以你必须做一个。如果你试图用纯粹的功能风格来编写你的程序,你只需就不会做出这样的事情。

但是,您可以使用sum函数返回总和或错误指示。实际上这种类型实际上通常以名称Either而知道。然后,您可以轻松地创建一个调用可能返回错误的大量计算的函数,并返回其他计算中遇到的所有错误的列表。这与你所谈论的非常接近;它只是显式返回而不是全局。请记住,当你编写一个功能程序时,问题是“如何制作一个具有我想要的行为的程序?”不是,“我将如何复制在另一种编程风格中采用的一种特定方法?”。 “全局状态错误流”是意味着而不是结束。您不能在纯函数样式中使用全局状态错误流,否。但问问自己,你使用全局状态错误流实现;不管它是什么,你可以实现在函数式编程中,只是没有相同的机制。

询问纯函数式编程是否可以实现一种依赖于副作用的特定技术,就像询问如何使用面向对象编程中的汇编技术。面向对象提供不同的工具供您用来解决问题;限制自己使用这些工具来模拟不同的工具集并不是一种有效的方法。


在回应评论:如果你想实现与您的错误流记录错误消息到终端的东西,那么是的,在一定程度上的代码将不得不做的IO去做。

打印到终端就像其他任何IO一样,没有什么特别的特别之处,它使得它值得挑选出来,因为状态似乎特别不可避免。因此,如果这会将您的问题变成“纯粹的功能性程序如何处理IO?”,那么无疑有许多重复的问题,更不用说很多博客文章和教程正是针对这个问题。对于纯编程语言的实现者和使用者来说,这不是一个突然的惊喜,这个问题已经存在了数十年了,并且已经有一些非常复杂的想法被应用于答案中。

在不同的语言中有不同的方法(在Haskell中有IO monad,在水星中有独特的模式,在Haskell的历史版本中有懒惰的请求和响应流等)。其基本思想是提出一个可由纯代码操作的模型,并将模型的操作与语言实现中的实际不纯操作联系起来。这可以让你保持纯度的好处(适用于纯代码的证据,但不适用于普通的不纯代码仍然适用于使用纯IO模型的代码)。

纯模型必须小心设计,使你不能真正用它做任何事情没有意义,在实际IO方面。例如,水星确实IO具有你写的程序你绕过宇宙的当前状态仿佛作为一个额外的参数。这个纯粹的模型准确地表示了依赖于并影响程序之外的宇宙的操作的行为,但只有当系统中的任何一个时刻都有一个宇宙状态时,它才会贯穿整个程序,从头到尾。所以有一些限制

  1. 类型io是抽象的,所以没有办法构造该类型的值;唯一的办法就是从你的调用者那里得到一个。一个io的值通过语言实现传递给main谓词,以完成整个事情。
  2. 传递给mainio值的方式声明,这样它是独一无二的。这意味着你不能做可能导致它重复的事情,比如将它放在一个容器中,或者将相同的io值传递给多个不同的调用。独特的模式可确保当你经过它一旦值是“死”的,不能被其他任何地方通过您只能在io值个屁也采用了独特的模式的谓词,并尽快。

注意,即使在必要的程序,你获得了很大的灵活性,如果你有你的错误日志记录系统返回的错误信息流,然后只实际上使打印这些接近决策程序的最外层。如果您的日志呼叫被直接立即以书面形式输出,这里只是几件事情,我能想到的把我的头顶部是变得更难有这样一个系统来做:

  • 预测执行的计算,看看是否它未能通过检查是否它发出的所有错误
  • 将多个高级别系统到一个单一的系统中,添加标记日志以每个系统区分
  • 的Emit调试且仅当还存在一个错误消息信息登录消息(所以输出是干净的,当有调试任何错误,并含有丰富的细节时,有)
+0

我明白你的意思了,但让我们假设系统有一个终端来打印信息。某处,_some_代码必须触及这个全局状态的对象,不是? –

+1

@CoreXii是的,一些必要的位本质上是不纯的。我建议你阅读Simon Peyton Jones的[解决笨拙的小队](http://research.microsoft.com/en-us/um/people/simonpj/papers/marktoberdorf/)。虽然细节现在已经过时,但对于Haskell如何解决这些问题,这是一个非常可读的阐述。其他语言使用不同的方法(我听说过的关键字:唯一性打字,效果系统),但我没有资格谈论这些。 – delnan

+0

@CoreXii我在回答中增加了一些更多的散漫内容,希望能够解决您的问题。 – Ben