可以做任何事情来定义未定义值的Show实例吗?也许存在一些GHC扩展?我想要这样的东西:
> print (1,undefined)
(1,"undefined")
答案 0 :(得分:4)
根据Haskell 2010 report, chapter 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"
由于打印值包括评估它,因此总是会出错。
答案 1 :(得分:2)
底值(其中undefined
是一种风味)是一个从未构造的值,因此无法观察到。这意味着您也无法打印它。此值无法与其他语言的null
进行比较,通常可以观察甚至检查。
将undefined
以及error "blah"
和所有其他底部视为等效于无限循环的结果是有用的。永远不会构造无限循环的结果,因此无法观察到。
答案 2 :(得分:1)
更概念性地说:“未定义”不是像'X'那样的值。 'X'值的类型为Char。 “undefined”有哪些类型?符号“undefined”是多态的,它可以是任何类型(任何类型的*)。
在类型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"
但正如您所看到的那样,通过永远不会检查该值来避免未定义的错误。所以这有点无用。
您可以创建自己的类型类和在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'需要强制整个String而不仅仅是WHNF。
答案 3 :(得分:0)
尽管(正如其他人已经指出的那样)您无法为Show
指定undefined
个实例,但您可以使用catch
整理解决方法以下代码:
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)