显示未定义的实例

时间:2012-05-24 13:50:14

标签: haskell undefined

可以做任何事情来定义未定义值的Show实例吗?也许存在一些GHC扩展?我想要这样的东西:

> print (1,undefined)

(1,"undefined")

4 个答案:

答案 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)