Show for IO types
Asked Answered
C

2

8

I have a data type which contains an IORef as an important element. This means there is not a clean way to make it a member of the show type class. This is not too bad as I have a print function in the IO monad for this type. But it is annoying in GHCi in that every time I return one of these thing as a result I get an error stating that it cannot be shown.

Is there a way to get GHCi, which operates in the IO monad anyway, to use an IO action to show a result? If not, would there be any negative consequences to writing show a = unsafePerformIO $ print a?

Cleanshaven answered 30/11, 2011 at 20:10 Comment(1)
As far as I know, there's no way to tell ghci to use a different function than show to display results. However, you can define a show instance for your datatype that simply displays "<ioref>" or the like for the ioref. That's probably slightly cleaner, if less convenient, than using unsafePerformIO.Chili
A
13

Have you considered adding to your .ghci file something like:

instance (Show a) => Show (IORef a) where
    show a = show (unsafePerformIO (readIORef a))

It isn't safe at all, but if this is just for your personal use perhaps that is OK.

For more general use the previously given answers look good to me. That is, either define a static "I can't show this" message:

instance Show (IORef a) where
    show _ = "<ioref>"

This would give something like:

> runFunc
MyStruct <ioref> 4 "string val"

Or use a custom function. I suggest making a class and lifting all the Show instances:

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

Giving the output (untested, this is just hand-written):

> myFunc >>= showIO
MyStruct "My String in an IORef" 4 "string val"
Americanism answered 30/11, 2011 at 22:17 Comment(1)
Note that these ShowIO instances require the OverlappingInstances extension. It's pretty dodgy, although possible less so than unsafePerformIO. Certainly helpful for development.Brawn
G
3

ghci has three cases for return values:

  1. Show a => a: Just run show and print it
  2. Show a => IO a: Execute the action, run show and print
  3. IO (): print nothing

So usually, if you type an IO action, it get's executed and the result gets printed if it's not (). Let's try it:

ghci>15
15
ghci>'a' : 'b' : 'c' : []
"abc"
ghci>putStrLn "Hello, world!"
Hello, world!
ghci>putStrLn "Hello, world!" >> return 42
Hello, world!
42
ghci>

If you want to print something different, the best way is probably to write a custom function and stick it in front of each line you want to see:

myShowFun :: ... -> IO String

ghci> myShowFun $ ...
foobar
Goiter answered 30/11, 2011 at 20:16 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.