语义近似顺序表明如果函数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
。
某处有错误吗?
答案 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 undefined
和f "test"
都等于MkIO
。从指称语义的角度来看,这对应于解释
[[
IO t
]] = {⊥< ⊤}
由于我们可以对IO操作执行的唯一操作是seq
并将它们组合到其他IO操作中,因此它是完全一致的指称语义,不会影响您谈论语义的能力。像length :: [Bool] -> Integer
这样的东西。它恰好对于理解执行IO操作时发生的事情毫无用处。但是如果你想在指称语义中对待它,除了例外之外你还会遇到很多困难。