我有一个数据类型,其中包含IORef作为一个重要元素。这意味着没有一种简单的方法将其作为show
类型类的成员。对于这种类型,我在IO单子中有一个print
函数,所以这不算太糟糕。但是,在GHCi中,每次我返回这些内容作为结果时,都会出现错误,指出它无法显示。
是否有一种方法可以让在IO单子中运行的GHCi使用IO操作来显示结果?如果没有,编写show a = unsafePerformIO $ print a
会有什么负面影响吗?
我有一个数据类型,其中包含IORef作为一个重要元素。这意味着没有一种简单的方法将其作为show
类型类的成员。对于这种类型,我在IO单子中有一个print
函数,所以这不算太糟糕。但是,在GHCi中,每次我返回这些内容作为结果时,都会出现错误,指出它无法显示。
是否有一种方法可以让在IO单子中运行的GHCi使用IO操作来显示结果?如果没有,编写show a = unsafePerformIO $ print a
会有什么负面影响吗?
您是否考虑过在您的 .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"
ghci有三种返回值的情况:
Show a => a
:只需运行show并打印即可。Show a => IO a
:执行操作,运行show并打印。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