为什么Haskell异常只能在IO monad中被捕获? [英] Why can Haskell exceptions only be caught inside the IO monad?

查看:180
本文介绍了为什么Haskell异常只能在IO monad中被捕获?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

解决方案

一个人可以解释为什么异常可能会被抛出IO单体之外,原因是 Haskell的指称语义

$ (纯)Haskell函数的一个整洁性质是其单调性 - 更多定义的参数产生更多的定义值。这个属性非常重要,例如关于递归函数的理由(阅读文章了解为什么)。



根据定义,异常的表示是底部, _ | _ ,poset中的最小元素对应于给定类型。因此,为了满足单调性要求,以下不等式需要适用于Haskell函数的任何指标 f

  f(_ | _)< = f(X)

现在,如果我们可以捕获异常,我们可以通过识别底部(捕获异常)并返回更多的定义值来破坏这种不平等:

  fx = case catch(seq x True)(\exception  - > False)
True - > - 没有例外
undefined
False - > - 有一个例外,返回定义值
42

这是完整的工作演示(需要base-4 Control.Exception):

  import Prelude hiding(catch)
import System.IO.Unsafe(unsafePerformIO )
import qualified Control.Exception as E

catch :: a - > (E.SomeException - > a) - > a
catch xh = unsafePerformIO $ E.catch(return $!x)(return。h)

fx = case catch(seq x True)(\exception - > False)of
True - > - 没有例外
undefined
False - > - 有一个例外,返回定义的值
42

另一个原因是,TomMD指出正在打破参照透明度。你可以平等地替换平等的东西,并得到另一个答案。 (等同于指称意义上,即它们表示相同的值,而不在 == 中)。



我们这样做考虑以下表达式:

  let x = x in x 

这是一个非终止的递归,所以它从来没有给我们任何信息,因此也由 _ | _ 。如果我们能够捕获异常,我们可以编写函数f,例如

  f undefined = 0 
f(let x = x in x)= _ | _

(后者对于严格的函数始终是真的,因为Haskell不提供检测非终止计算的方法 - 原则上不能因为停止问题。)


Can anybody explain why exceptions may be thrown outside the IO monad, but may only be caught inside it?

解决方案

One of the reasons is the denotational semantics of Haskell.

One of the neat properties of (pure) Haskell functions is their monotonicity -- more defined argument yields more defined value. This property is very important e.g. to reason about recursive functions (read the article to understand why).

Denotation of exception by definition is the bottom, _|_, the least element in poset corresponding to the given type. Thus, to satisfy monotonicity requirement, the following inequality needs to hold for any denotation f of Haskell function:

f(_|_) <= f(X)

Now, if we could catch exceptions, we could break this inequality by "recognizing" the bottom (catching the exception) and returning more defined value:

f x = case catch (seq x True) (\exception -> False) of
        True -> -- there was no exception
            undefined
        False -> -- there was an exception, return defined value
            42

Here's complete working demonstration (requires base-4 Control.Exception):

import Prelude hiding (catch)
import System.IO.Unsafe (unsafePerformIO)
import qualified Control.Exception as E

catch :: a -> (E.SomeException -> a) -> a
catch x h = unsafePerformIO $ E.catch (return $! x) (return . h)

f x = case catch (seq x True) (\exception -> False) of
        True -> -- there was no exception
            undefined
        False -> -- there was an exception, return defined value
            42

Another reason, as TomMD noted, is breaking referential transparency. You could replace equal things with equal and get another answer. (Equal in denotational sense, i.e. they denote the same value, not in == sense.)

How would we do this? Consider the following expression:

let x = x in x

This is a non-terminating recursion, so it never returns us any information and thus is denoted also by _|_. If we were able to catch exceptions, we could write function f such as

f undefined = 0
f (let x = x in x) = _|_

(The latter is always true for strict functions, because Haskell provides no means to detect non-terminating computation -- and cannot in principle, because of the Halting problem.)

这篇关于为什么Haskell异常只能在IO monad中被捕获?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆