"错误"功能的存在如何影响Haskell的纯度?

The*_*kle 7 error-handling haskell functional-programming exception purely-functional

我一直想知道Haskell异常系统如何适应整个"纯函数式语言"的东西.例如,请参阅下面的GHCi会话.

GHCi, version 8.0.1: http://www.haskell.org/ghc/  :? for help
Prelude> head []
*** Exception: Prelude.head: empty list
Prelude> :t head
head :: [a] -> a
Prelude> :t error
error :: [Char] -> a
Prelude> error "ranch"
*** Exception: ranch
CallStack (from HasCallStack):
  error, called at <interactive>:4:1 in interactive:Ghci1
Prelude>
Run Code Online (Sandbox Code Playgroud)

头的类型是[a] - > a.但是当你在空列表的特殊情况下调用它时,你会得到一个例外.但是类型签名中没有考虑此异常.

如果我没记错的话,在模式匹配过程中出现故障时,情况类似.类型签名所说的并不重要,如果你没有考虑到每种可能的模式,你就有可能抛出异常.

我没有一个简明扼要的问题要问,但我的头脑正在游泳.将这个奇怪的异常系统添加到其他纯粹优雅语言的动机是什么?它仍然是纯净的,但我只是缺少一些东西?如果我想利用这个异常功能,我将如何去做(即如何捕获和处理异常?还有什么我可以用它们做的吗?)例如,如果我编写使用它的代码"头"功能,当然我应该采取预防措施,以一个空列表以某种方式走私自己的情况.

Ant*_*sky 11

你混淆了两个概念:纯度总体.

  • Purity说功能没有副作用.
  • Totality说每个函数都终止并产生一个值.

Haskell 纯粹,但并不完全.

之外IO,nontermination(例如let loop = loop in loop)和异常(如error "urk!")是相同的-非终止和特殊条款,强迫时,不计算值.Haskell的设计者想要一种图灵完备的语言 - 根据停止问题 - 意味着它们总体上是完整的.一旦你有了不确定性,我想你也可能也有异常 - 定义error msg = error msgerror永远不做任何事情的调用在实践中比在有限的时间内实际看到你想要的错误消息更不令人满意!

一般来说,你是对的 - 部分函数(那些没有为每个输入值定义的函数head)都是丑陋的.现代Haskell通常更喜欢通过返回MaybeEither值来编写总函数,例如

safeHead :: [a] -> Maybe a
safeHead []    = Nothing
safeHead (x:_) = Just x

errHead :: [a] -> Either String a
errHead []    = Left "Prelude.head: empty list"
errHead (x:_) = Right x
Run Code Online (Sandbox Code Playgroud)

在这种情况下,Functor,Applicative,Monad,MonadError,Foldable,Traversable,等,使得机械结合这些总的功能和对自己的成绩很容易的工作.

您是否真的在代码中遇到异常 - 例如,您可能会使用error检查代码中您认为已执行的复杂的不变量,但是您有一个错误 - 您可以将其捕获IO.这回到了为什么可以与异常进行交互的问题IO- 这不会导致语言不纯吗?答案与我们为什么可以进行I/O IO或使用可变变量的问题相同 - 评估类型的值IO A不会产生它所描述的副作用,它只是一个描述什么是程序可以做到.(互联网上的其他地方有更好的描述;例外与其他效果没有任何不同.)

(另请注意,有一个单独的,但相关的异常体系 IO,这是当如试图读取一个文件,是不是有使用.人们经常用这个异常系统OK,适可而止,因为既然你在IO你已经使用不纯的代码.)