Показать для типов ввода-вывода - PullRequest
7 голосов
/ 01 декабря 2011

У меня есть тип данных, который содержит IORef в качестве важного элемента.Это означает, что нет простого способа сделать его членом класса show.Это не так уж плохо, поскольку у меня есть функция print в монаде ввода-вывода для этого типа.Но в GHCi раздражает то, что каждый раз, когда я возвращаю одну из этих вещей, в результате я получаю сообщение о том, что ее невозможно отобразить.в любом случае, использовать действие ввода-вывода, чтобы показать результат?Если нет, будут ли какие-либо негативные последствия для написания show a = unsafePerformIO $ print a?

Ответы [ 2 ]

11 голосов
/ 01 декабря 2011

Рассматривали ли вы добавление в файл .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"
2 голосов
/ 01 декабря 2011

ghci имеет три случая для возвращаемых значений:

  1. Show a => a: просто запустите show и напечатайте его
  2. Show a => IO a: выполните действие, запустите show и напечатайте
  3. 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
...