2011-11-30 8 views
7

Tengo un tipo de datos que contiene un IORef como un elemento importante. Esto significa que no hay una forma clara de hacerlo miembro de la clase de tipo show. Esto no es tan malo ya que tengo una función print en la mónima IO para este tipo. Pero es molesto en GHCi que cada vez que devuelvo una de estas cosas como resultado recibo un error que indica que no se puede mostrar.Mostrar para IO tipos

¿Hay alguna manera de hacer que GHCi, que opera en la mónada IO de todos modos, use una acción IO para mostrar un resultado? Si no, ¿habría alguna consecuencia negativa al escribir show a = unsafePerformIO $ print a?

+3

Por lo que yo sé, no hay manera de saber ghci para usar una función diferente a 'show' para mostrar los resultados. Sin embargo, puede definir una instancia de espectáculo para su tipo de datos que simplemente muestre "" o similar para el ioref. Eso es probablemente un poco más limpio, si es menos conveniente, que usar 'inseguroPerformIO'. – sclv

Respuesta

11

Tener Ha considerado añadiendo a su archivo .ghci algo como:

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

no es seguro en absoluto, pero si esto es sólo para su uso personal tal vez eso está bien.

Para un uso más general, las respuestas dadas anteriormente se ven bien para mí. Es decir, o bien definir un estático "No puedo mostrar esta" mensaje:

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

Esto daría algo así como:

> runFunc 
MyStruct <ioref> 4 "string val" 

O utilizar una función personalizada. Sugiero hacer una clase y el levantamiento de todas las Mostrar instancias:

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 

Dando la salida (no probado, esto es sólo escrito a mano):

> myFunc >>= showIO 
MyStruct "My String in an IORef" 4 "string val" 
+1

Tenga en cuenta que estas instancias 'ShowIO' requieren la extensión OverlappingInstances. Es bastante dudoso, aunque es posible menos que 'inseguroPerformIO'. Ciertamente útil para el desarrollo. –

2

ghci tiene tres casos para valores de retorno:

  1. Show a => a: espectáculo Sólo tiene que ejecutar y imprimirlo
  2. Show a => IO a: Ejecutar la acción, espectáculo de correr y de impresión
  3. IO(): Impresión nada

Por lo general, si escribe una acción IO, se ejecuta y el resultado se imprime si no es (). Vamos a intentarlo:

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

Si desea imprimir algo diferente, la mejor manera es probable que escribir una función personalizada y pegarlo en la parte frontal de cada línea que desea ver:

myShowFun :: ... -> IO String 

ghci> myShowFun $ ... 
foobar