IO类型展示

8

我有一个数据类型,其中包含IORef作为一个重要元素。这意味着没有一种简单的方法将其作为show类型类的成员。对于这种类型,我在IO单子中有一个print函数,所以这不算太糟糕。但是,在GHCi中,每次我返回这些内容作为结果时,都会出现错误,指出它无法显示。

是否有一种方法可以让在IO单子中运行的GHCi使用IO操作来显示结果?如果没有,编写show a = unsafePerformIO $ print a会有什么负面影响吗?


3
据我所知,无法告诉ghci使用不同于“show”的函数显示结果。 但是,你可以为你的数据类型定义一个显示实例,该实例仅显示"<ioref>"或类似于ioref的内容。 这可能比使用“unsafePerformIO”更简洁一些,尽管不太方便。 - sclv
2个回答

12

您是否考虑过在您的 .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"

1
请注意,这些“ShowIO”实例需要使用OverlappingInstances扩展。这可能有点不可靠,但可能比“unsafePerformIO”要少。对于开发来说肯定很有帮助。 - John L

3

ghci有三种返回值的情况:

  1. Show a => a:只需运行show并打印即可。
  2. Show a => IO a:执行操作,运行show并打印。
  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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接