显示IO类型

时间:2011-11-30 20:10:28

标签: haskell ghci io-monad ioref unsafe-perform-io

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

有没有办法让IOC无论如何在IO monad中运行,使用IO动作来显示结果?如果没有,写show a = unsafePerformIO $ print a是否会产生任何负面影响?

2 个答案:

答案 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有三种返回值:

  1. Show a => a:只需运行show并将其打印
  2. Show a => IO a:执行操作,运行show and print
  3. IO ():不打印任何内容
  4. 通常情况下,如果您键入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