catch违反了语义逼近顺序?

时间:2017-03-04 15:34:00

标签: haskell

语义近似顺序表明如果函数f在其参数不是一个时被定义,则f在该参数中是常量(它不使用它)。但请考虑这个功能,

import Control.Exception

handleAll :: SomeException -> IO ()
handleAll e = putStrLn "caught"

f :: String -> IO ()
f x = catch (putStrLn x) handleAll

f undefined在GHCi中显示caught,因此看起来已定义。但是f在其参数中不是常量,因为f "test"显示test

某处有错误吗?

1 个答案:

答案 0 :(得分:8)

要正确建模异常和catch,您需要一个更丰富的术语指称语义,以区分异常和非终止(并区分不同的异常)。有关GHC实现的语义,请参阅A semantics for imprecise exceptions (pdf)

请注意,这对"纯片段"的指称语义没有影响。 Haskell,因为你没有办法观察纯代码中IO a值之间的区别(除了底部与非底部之外)。

澄清我的意思是"纯片段"在Haskell中,想象将IO类型定义为

data IO a = MkIO

catch

catch a h = MkIO

现在f没问题,因为f undefinedf "test"都等于MkIO。从指称语义的角度来看,这对应于解释

  

[[IO t]] = {⊥< ⊤}

由于我们可以对IO操作执行的唯一操作是seq并将它们组合到其他IO操作中,因此它是完全一致的指称语义,不会影响您谈论语义的能力。像length :: [Bool] -> Integer这样的东西。它恰好对于理解执行IO操作时发生的事情毫无用处。但是如果你想在指称语义中对待它,除了例外之外你还会遇到很多困难。