3

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

> print (1,undefined)

(1,"undefined")
4

4 回答 4

4

根据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"

由于打印一个值包括评估它,这总是会出错。

于 2012-05-24T13:59:24.080 回答
2

底部值(其中undefined一种风味)是一个从未构造过的值,因此无法观察到。这意味着您也无法打印它。该值无法与null其他语言进行比较,通常可以观察甚至检查。

undefined将以及error "blah"所有其他底部视为等效于无限循环的结果是很有用的。永远不会构造无限循环的结果,因此无法观察到。

于 2012-05-24T15:13:51.757 回答
1

从概念上讲:“未定义”不是像“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。

于 2012-05-24T17:21:51.793 回答
0

即使(正如其他人已经指出的那样)您不能为 指定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)
于 2012-05-24T14:36:02.113 回答