Search code examples
haskellghciio-monadiorefunsafe-perform-io

Show for IO types


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?


Solution

  • 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"