可以做任何事情来为未定义的值定义 Show 实例吗?也许存在一些 GHC 扩展?我想要这样的东西:
> print (1,undefined)
(1,"undefined")
根据Haskell 2010 报告第 9 章,评估undefined
总是会导致错误:
-- It is expected that compilers will recognize this and insert error
-- messages that are more appropriate to the context in which undefined
-- appears.
undefined :: a
undefined = error "Prelude.undefined"
由于打印一个值包括评估它,这总是会出错。
底部值(其中undefined
一种风味)是一个从未构造过的值,因此无法观察到。这意味着您也无法打印它。该值无法与null
其他语言进行比较,通常可以观察甚至检查。
undefined
将以及error "blah"
所有其他底部视为等效于无限循环的结果是很有用的。永远不会构造无限循环的结果,因此无法观察到。
从概念上讲:“未定义”不是像“X”这样的值。“X”值的类型为 Char。“未定义”有什么类型?符号“未定义”是多态的,它可以有任何类型(任何类型的 *)。
类型类如“Show t”在类型 t 上调度。所以不同的类型可以并且确实有不同的显示功能来显示它们。哪个函数得到你的“未定义”取决于类型。
在 GHCI 中,大多数多态类型默认为 (),因此它可以运行命令。可以为不查看值的新类型创建 show 函数:
Prelude> data Test = Test
Prelude> instance Show Test where show x = "I did not look at x"
Prelude> show Test
"I did not look at x"
Prelude> show (undefined :: Test)
"I did not look at x"
但是正如您所看到的,这通过根本不检查值来避免 undefined 的错误。所以这有点没用。
您可以制作自己的类型类和在 IO 中运行并捕获错误并执行您想要的操作的打印机器:
import Control.Exception
perr s = do x <- try (evaluate (show s)) :: IO (Either SomeException String)
return (either show id x))
以上将错误转换为错误的字符串形式:
Prelude Control.Exception> perr True
"True"
Prelude Control.Exception> perr (undefined :: Bool)
"Prelude.undefined"
注意:更好的“perr”需要强制使用整个字符串,而不仅仅是 WHNF。
即使(正如其他人已经指出的那样)您不能为 指定Show
实例undefined
,您也可以通过使用catch
以下代码中的 as 来组合一种解决方法:
import qualified Control.Exception as C
import System.IO.Unsafe (unsafePerformIO)
showCatch :: (Show a) => a -> IO String
showCatch = showCatch' "undefined"
showCatch' :: (Show a) => String -> a -> IO String
showCatch' undef x = C.catch (C.evaluate (show x)) showUndefined
where
showUndefined :: C.ErrorCall -> IO String
showUndefined _ = return undef
unsafeShowCatch :: (Show a) => a -> String
unsafeShowCatch x = unsafePerformIO (showCatch x)
但是这个例子只适用于简单的表达式:
*Main> let v1 = showCatch 1
v1 :: IO String
*Main> let v2 = showCatch $ if True then undefined else 0
v2 :: IO String
*Main> v1
"1"
*Main> v2
"undefined"
*Main> let v3 = unsafeShowCatch 1
v3 :: String
*Main> let v4 = unsafeShowCatch $ undefined
v4 :: String
*Main> v3
"1"
*Main> v4
"undefined"
它不适用于像
showCatch (1,undefined)