我有一个数据类型,其中包含IORef作为重要元素。这意味着没有一种干净的方法可以使它成为show
类型类的成员。这不是太糟糕,因为我在IO monad中有这种类型的print
函数。但是在GHCi中很烦人,因为每当我返回其中一个东西时,我都会收到错误声明它无法显示。
有没有办法让IOC无论如何在IO monad中运行,使用IO动作来显示结果?如果没有,写show a = unsafePerformIO $ print a
是否会产生任何负面影响?
答案 0 :(得分: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"
答案 1 :(得分:2)
ghci有三种返回值:
Show a => a
:只需运行show并将其打印Show a => IO a
:执行操作,运行show and print 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