定义一个函数a - > String,适用于没有Show的类型?

Joh*_*kin 7 haskell class

我想定义一个可以"显示"任何类型的值的函数,对于实际定义Show实例的类型具有特殊行为:

magicShowCast :: ?

debugShow :: a -> String
debugShow x = case magicShowCast x of
    Just x' -> show x'
    Nothing -> "<unprintable>"
Run Code Online (Sandbox Code Playgroud)

当出现问题时,这将用于向错误消息添加更详细的信息:

-- needs to work on non-Showable types
assertEq :: Eq a => a -> a -> IO ()
assertEq x y = when (x /= y)
    (throwIO (AssertionFailed (debugShow x) (debugShow y)))

data CanShow = CanShow1
             | CanShow 2
    deriving (Eq, Show)

data NoShow = NoShow1
            | NoShow2
    deriving (Eq)

-- AssertionFailed "CanShow1" "CanShow2"
assertEq CanShow1 CanShow2

-- AssertionFailed "<unprintable>" "<unprintable>"
assertEq NoShow1 NoShow2
Run Code Online (Sandbox Code Playgroud)

有没有办法做到这一点?我尝试使用GADT,存在类型和模板haskell的各种组合,但这些都不够,或者我无法弄清楚如何正确应用它们.

C. *_*ann 14

真正的答案:你做不到.Haskell故意没有定义一个通用的"序列化到字符串"函数,并且能够在没有某些类型类约束的情况下这样做会违反整个城镇的参数化.可怕,只是可怕.

如果您不明白为什么会出现问题,请考虑以下类型签名:

something :: (a, a) -> b -> a
Run Code Online (Sandbox Code Playgroud)

你会如何实现这个功能?泛型类型意味着它必须是const . fst或者const . snd,对吧?嗯.

something (x,y) z = if debugShow z == debugShow y then y else x
Run Code Online (Sandbox Code Playgroud)
> something ('a', 'b') ()
'a'
> something ('a', 'b') 'b'
'b'
Run Code Online (Sandbox Code Playgroud)

Oooooooops!因为能够以任何理智的方式推理您的程序.就是这样,show结束了,回家了,它一直很有趣.


可怕的,没有好的,不明智的答案:当然,如果你不介意无耻地作弊.我是否提到上面的例子是一个真正的GHCi会话?哈哈.

import Control.Exception
import Control.Monad
import GHC.Vacuum

debugShow :: a -> String
debugShow = show . nameGraph . vacuumLazy

assertEq :: Eq a => a -> a -> IO ()
assertEq x y = when (x /= y) . throwIO . AssertionFailed $ 
    unlines ["assertEq failed:", '\t':debugShow x, "=/=", '\t':debugShow y]

data NoShow = NoShow1
            | NoShow2
    deriving (Eq)
Run Code Online (Sandbox Code Playgroud)
> assertEq NoShow1 NoShow2
*** Exception: assertEq failed:
    [("|0",["NoShow1|1"]),("NoShow1|1",[])]
=/=
    [("|0",["NoShow2|1"]),("NoShow2|1",[])]
Run Code Online (Sandbox Code Playgroud)

哦.好.这看起来像一个奇妙的想法,不是吗.

无论如何,这并没有给你你想要的东西,因为没有明显的方法可以回到适当的Show实例.另一方面,这可以让你做更多的show事情,所以也许这是一个洗.

但是说真的.不要在实际的工作代码中执行此操作.好的,错误报告,调试,记录......这是有道理的.但除此之外,它可能是非常不明智的.