勺子在Haskell中不安全吗?

时间:2013-02-05 15:24:20

标签: haskell

因此Haskell中有一个名为spoon的库,可以让我这样做

safeHead :: [a] -> Maybe a
safeHead = spoon . head

但它也让我这样做

>>> spoon True             :: Maybe Bool
Just True
>>> spoon (error "fork")   :: Maybe Bool
Nothing
>>> spoon undefined        :: Maybe Bool
Nothing
>>> spoon (let x = x in x) :: Maybe Bool
<... let's just keep waiting...>

在某些情况下似乎非常有用,但它也违反了指称语义(据我的理解),因为它让我能够区分的语义原像中的不同事物。这比throw / catch更强大,因为它们可能具有由continuation定义的语义。

>>> try $ return (error "thimble") :: IO (Either SomeException Bool)
Right *** Exception: thimble

所以我的问题是:有人可以恶意使用勺子打破类型安全吗?便利值得危险吗?或者,更现实地说,有一种合理的方式使用它可能会侵蚀某人对某项计划意义的信心吗?

2 个答案:

答案 0 :(得分:37)

有一个棘手的问题,如果你使用它,做一个看似无辜的重构的东西可以改变一个程序的行为。没有任何花里胡哨,就是这样:

f h x = h x
isJust (spoon (f undefined)) --> True

但也许这本书中最常见的haskell转换,eta收缩,到f,给出了

f h = h
isJust (spoon (f undefined)) --> False

由于seq的存在,Eta收缩已经不是保留语义;但没有勺子eta收缩只能将终止程序变成错误;使用勺子eta收缩可以将终止程序更改为不同的终止程序。

正式地,spoon不安全的方式是non-monotone on domains(因此可以根据它定义函数);而没有spoon,每个函数都是单调的。所以技术上你失去了正式推理的有用属性。

提出一个现实生活中的例子,说明什么时候这很重要,留给读者练习(阅读:我认为现实生活中不太重要 - 除非你开始滥用它;例如使用undefined Java程序员使用null

的方式

答案 1 :(得分:13)

你不能用unsafeCoercespoon,如果这是你得到的。它正如它看起来一样不合理,并且正如它所看到的那样严重违反Haskell语义。但是,您不能使用它来创建段错误或类似的东西。

然而,通过违反Haskell语义, 使代码更难以推理,并且例如,带勺子的safeHead必然比直接写的safeHead效率低。