我有一个包含IORef作为重要元素的数据类型。这意味着没有一种干净的方法使其成为show
类型类的成员。这不是太糟糕,因为我在IO单子中有一个print
函数。但是在GHCi中它很烦人,因为每次我返回这些东西之一时,我都会得到一个错误,指出它无法显示。
是否有一种方法来获得GHCi,它在IO单子中操作,使用IO操作来显示结果?如果没有,写show a = unsafePerformIO $ print a
会有什么不好的后果吗?
您是否考虑过在.ghci文件中添加如下内容:
instance (Show a) => Show (IORef a) where
show a = show (unsafePerformIO (readIORef a))
这是不安全的,但如果这只是你个人使用,也许是可以的。
对于更一般的用法,前面给出的答案看起来不错。也就是说,要么定义一个静态的"I can't show this"消息:
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"
ghci有三种返回值:
-
Show a => a
:只需运行show并打印它 -
Show a => IO a
:执行动作,运行显示并打印 -
IO ()
: print nothing
通常,如果你输入一个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