到目前为止,我已经看到了许多"也许"某些可能导致Γ的偏函数的版本,如read
的readMaybe
和head
的listToMaybe
;有时我想知道我们是否可以推广这个想法,并计算出这样一个函数safe :: (a -> b) -> (a -> Maybe b)
,将任何部分函数转换为它们更安全的总替换函数,在原始函数中调用错误堆栈的任何实例上返回Nothing
。到目前为止,我还没有找到一种方法来实现这样的safe
函数或现有的类似实现,我开始怀疑这个想法是否真的可行。
底部实际上有两种,非终止和错误。由于显而易见的原因,您无法捕获非终止,但您可以捕获错误。这是一个快速组合的版本(我不是专家,所以可能有更好的方法(
{-# LANGUAGE ScopedTypeVariables #-}
import Control.Exception
import System.IO.Unsafe
safe f = unsafePerformIO $ do
z <- try (evaluate f)
let r = case z of
Left (e::SomeException) -> Nothing
Right k -> Just k
return r
以下是的一些例子
*Main > safe (head [42])
Just 42
*Main > safe (head [])
Nothing
*Main λ safe (1 `div` 0)
Nothing
*Main λ safe (1 `div` 2)
Just 0
不,这是不可能的。它违反了名为";单调性";,它说,一个值在处理过程中不能变得更明确。你不能在底部分支——试图处理一个值总是会导致底部。
或者至少,Haskell评估所基于的领域理论都是如此。但Haskell有一些额外的特征,领域理论没有。。。就像执行IO
操作与求值不同,unsafePerformIO
让您在求值中隐藏执行一样。勺子库将所有这些想法打包在一起,尽可能做到。这并不完美。它有漏洞,因为这不是你应该能做到的。但它在很多常见情况下都能做到。
考虑函数
collatz :: Integer -> ()
collatz 1 = ()
collatz n
| even n = collatz $ n`div`2
| otherwise = collatz $ 3*n + 1
(为了简单起见,假设Integer
是正整数的类型(
这是一个完整的函数吗?没人知道!据我们所知,它可能是总和,所以你提出的safe
-保护永远不会产生Nothing
。但也没有人找到它是完全的证据,所以如果safe
总是返回Just (collatz n)
,那么这可能仍然只是部分的。