2011-11-30 38 views
7

我有一個數據類型,其中包含一個IORef作爲一個重要的元素。這意味着沒有一種簡單的方法使其成爲show類型類的成員。這並不算太壞,因爲我在這個類型的IO monad中有一個print函數。但在GHCi中這是令人討厭的,因爲每次我返回其中一個結果時,我都會得到一個錯誤,指出它無法顯示。顯示IO類型

有沒有辦法讓GHCi在IO monad中運行,使用IO操作來顯示結果?如果沒有,編寫show a = unsafePerformIO $ print a會有什麼不利後果?

+3

據我所知,有沒有辦法告訴ghci使用與'show'不同的功能來顯示結果。但是,您可以爲數據類型定義一個show實例,該實例只顯示「」或類似的ioref。如果不太方便,那可能會比使用'unsafePerformIO'更簡潔。 – sclv

回答

11

有你認爲添加到您的.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" 

或者使用自定義功能。我建議做一個類,並解除所有的顯示實例:

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" 
+1

請注意,這些'ShowIO'實例需要OverlappingInstances擴展。雖然可能比'unsafePerformIO'更少,這是相當不妥的。肯定有助於發展。 –

2

ghci中有三種情況返回值:

  1. Show a => a:只要運行顯示和打印
  2. Show a => IO a:執行的操作,運行顯示和打印
  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