2011-11-30 33 views
7

Tôi có loại dữ liệu chứa IORef làm thành phần quan trọng. Điều này có nghĩa là không có cách nào để làm cho nó trở thành thành viên của lớp loại show. Điều này không quá tệ vì tôi có chức năng print trong đơn IO cho loại này. Nhưng nó gây phiền nhiễu trong GHCi ở chỗ mỗi khi tôi trả lại một trong những điều này, kết quả là tôi nhận được một lỗi nói rằng nó không thể được hiển thị.Hiển thị cho các loại IO

Có cách nào để nhận GHCi, hoạt động trong trình đơn IO hay không, để sử dụng tác vụ IO để hiển thị kết quả? Nếu không, sẽ có bất kỳ hậu quả tiêu cực nào khi viết show a = unsafePerformIO $ print a?

+3

Theo như tôi biết, không có cách nào để nói ghci để sử dụng một hàm khác với 'show' để hiển thị kết quả. Tuy nhiên, bạn có thể xác định một thể hiện chương trình cho kiểu dữ liệu của bạn chỉ đơn giản là hiển thị "" hoặc tương tự cho ioref. Đó có thể là hơi sạch hơn, nếu ít thuận tiện hơn là sử dụng 'unsafePerformIO'. – sclv

Trả lời

11

Có bạn coi thêm vào một cái gì đó của bạn tập tin .ghci như:

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

Nó không phải là an toàn ở tất cả, nhưng nếu điều này là chỉ dành riêng cho mục đích cá nhân của bạn có lẽ đó là OK.

Để sử dụng tổng quát hơn các câu trả lời đã cho trước đây có vẻ phù hợp với tôi. Đó là, một trong hai định nghĩa một tĩnh "Tôi không thể hiển thị này" thông điệp:

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

này sẽ cung cấp cho một cái gì đó như:

> runFunc 
MyStruct <ioref> 4 "string val" 

Hoặc sử dụng một chức năng tùy chỉnh. Tôi đề nghị thực hiện một lớp và nâng tất cả các Hiện trường:

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 đầu ra (chưa được kiểm tra, đây chỉ là viết tay):

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

Lưu ý rằng các trường hợp 'ShowIO' này yêu cầu phần mở rộng OverlappingInstances. Nó khá dodgy, mặc dù có thể ít hơn so với 'unsafePerformIO'. Chắc chắn hữu ích cho sự phát triển. –

2

ghci có ba trường hợp cho giá trị trả về:

  1. Show a => a: Chỉ cần chạy chương trình và in nó
  2. Show a => IO a: Thực hiện hành động, chạy chương trình và in
  3. IO(): print gì

Vì vậy, thông thường, nếu bạn gõ một hành động IO, nó sẽ được thực hiện và kết quả sẽ được in nếu nó không phải là (). Hãy thử nó:

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

Nếu bạn muốn in một cái gì đó khác nhau, cách tốt nhất có lẽ là để viết một chức năng tùy chỉnh và dính nó ở phía trước của mỗi dòng bạn muốn xem:

myShowFun :: ... -> IO String 

ghci> myShowFun $ ... 
foobar 
Các vấn đề liên quan