Haskell 显示IO类型

Haskell 显示IO类型,haskell,ghci,io-monad,ioref,unsafe-perform-io,Haskell,Ghci,Io Monad,Ioref,Unsafe Perform Io,我有一个数据类型,其中包含一个IORef作为一个重要元素。这意味着没有一种干净的方法使其成为showtype类的成员。这还不算太糟,因为对于这种类型,我在IO monad中有一个print函数。但在GHCi中很烦人,因为每次我返回这些东西中的一个,结果都会得到一个错误,说明它无法显示 有没有办法让在IO monad中运行的GHCi使用IO操作来显示结果?如果没有,编写show a=unsafePerformIO$print a是否会有任何负面后果 ghci的返回值有三种情况: Show a=>a

我有一个数据类型,其中包含一个IORef作为一个重要元素。这意味着没有一种干净的方法使其成为
show
type类的成员。这还不算太糟,因为对于这种类型,我在IO monad中有一个
print
函数。但在GHCi中很烦人,因为每次我返回这些东西中的一个,结果都会得到一个错误,说明它无法显示


有没有办法让在IO monad中运行的GHCi使用IO操作来显示结果?如果没有,编写
show a=unsafePerformIO$print a
是否会有任何负面后果

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
    

    您是否考虑过向.ghci文件中添加以下内容:

    instance (Show a) => Show (IORef a) where
        show a = show (unsafePerformIO (readIORef a))
    
    > runFunc
    MyStruct <ioref> 4 "string val"
    
    这是不安全的,但如果这只是为了你的个人使用,也许这是好的

    对于更一般的用途,我觉得前面给出的答案很好。也就是说,定义一条静态“我不能显示此”消息:

    给出输出(未测试,这只是手写):


    据我所知,没有办法告诉ghci使用不同于
    show
    的函数来显示结果。但是,您可以为数据类型定义一个show实例,该实例仅为ioref显示“”或类似内容。这可能比使用
    unsafePerformIO
    稍微干净一些,如果不方便的话。请注意,这些
    ShowIO
    实例需要重叠实例扩展。这是相当狡猾的,尽管可能比
    unsafePerformIO
    更狡猾。当然有助于发展。
    > runFunc
    MyStruct <ioref> 4 "string val"
    
    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"