3

所以今天我突然想到我可以表演一个小把戏。

{-# LANGUAGE TypeApplications #-}

import Control.Exception
import System.IO.Unsafe

catchPartial :: a -> Maybe a
catchPartial x =
    case unsafePerformIO $ try @ErrorCall (evaluate x) of
      Left _ -> Nothing
      Right x' -> Just x'

这是一个奇怪的小函数,它接受一个(可能未计算的)类型值a,将其计算为 WHNF,然后将error/转换undefinedNothing. 它确实有效。我可以在 Prelude 部分函数上使用它,比如toEnumhead

toEnum' :: Enum a => Int -> Maybe a
toEnum' n = catchPartial (toEnum n)

head' :: [a] -> Maybe a
head' xs = catchPartial (head xs)

 

*Main> toEnum' 0 :: Maybe Bool
Just False
*Main> toEnum' 1 :: Maybe Bool
Just True
*Main> toEnum' 2 :: Maybe Bool
Nothing
*Main> head' []
Nothing
*Main> head' [1, 2, 3]
Just 1

这似乎是 Prelude 的许多部分函数问题的包罗万象。而且,至少在我对它的原始测试中,它似乎工作得很好。然而我还没有看到它在任何地方使用过,而且我看到很多人抱怨 Prelude 有部分功能。我总是很警惕,并通过unsafePerformIOIO将错误分解以检测它只是危险信号。

所以我的问题是:我在这里没有看到什么基本问题?这实际上是合理的使用unsafePerformIO吗?运行起来是否过于昂贵(我没有对它进行性能基准测试)?是否存在一些奇怪的语义错误(seq可能涉及 )使其无法用于生产?

4

0 回答 0