7

我有一个包含 IORef 作为重要元素的数据类型。这意味着没有一种干净的方法可以使它成为show类型类的成员。这还不错,因为我print在 IO monad 中有一个针对这种类型的函数。但是在 GHCi 中很烦人,因为每次我返回其中一个结果时,我都会收到一个错误,指出它无法显示。

有没有办法让在 IO monad 中运行的 GHCi 使用 IO 动作来显示结果?如果没有,写作会有什么负面影响show a = unsafePerformIO $ print a吗?

4

2 回答 2

11

您是否考虑过在 .ghci 文件中添加如下内容:

instance (Show a) => Show (IORef a) where
    show a = show (unsafePerformIO (readIORef a))

这根本不安全,但如果这只是供您个人使用,也许没关系。

对于更一般的用途,以前给出的答案对我来说看起来不错。也就是说,要么定义一个静态的“我不能显示这个”消息:

instance Show (IORef a) where
    show _ = "<ioref>"

这将给出类似的东西:

> runFunc
MyStruct <ioref> 4 "string val"

或者使用自定义函数。我建议创建一个类并提升所有 Show 实例:

class ShowIO a where
    showIO :: a -> IO String

instance Show a => ShowIO a where
    showIO = return . show
instance ShowIO a => ShowIO (IORef a) where
    showIO a = readIORef a >>= showIO

给出输出(未经测试,这只是手写的):

> myFunc >>= showIO
MyStruct "My String in an IORef" 4 "string val"
于 2011-11-30T22:17:03.950 回答
2

ghci 有三种返回值的情况:

  1. Show a => a:只需运行显示并打印它
  2. Show a => IO a:执行动作,运行显示和打印
  3. IO (): 不打印

所以通常,如果你输入一个 IO 动作,它会被执行,如果不是,结果就会被打印出来()。让我们尝试一下:

ghci>15
15
ghci>'a' : 'b' : 'c' : []
"abc"
ghci>putStrLn "Hello, world!"
Hello, world!
ghci>putStrLn "Hello, world!" >> return 42
Hello, world!
42
ghci>

如果您想打印不同的内容,最好的方法可能是编写一个自定义函数并将其粘贴在您想要查看的每一行的前面:

myShowFun :: ... -> IO String

ghci> myShowFun $ ...
foobar
于 2011-11-30T20:16:39.520 回答