我有自定义数据类型Foo = Foo{ a :: Int, b :: Int}
,我正在尝试使Foo成为自定义读取实例。我已经有一个函数bar :: String -> Foo
,我尝试这样做:
instance Read (Foo a b) where
read s = bar s
但是当我将文件加载到GHCi中进行测试时,我收到以下错误:Fraction.hs:11:1: read' is not a (visible) method of class Read'
有人可以告诉我问题是什么以及我如何实际实例化这种类型?
答案 0 :(得分:18)
Read类型类没有直接声明read
;相反,它定义readsPrec
,它支持优先级(当read
涉及其他类型元素的复杂数据类型的值时,这很重要。使用deriving (Read)
时获得的定义大致类似于
instance (Read a) => Read (Tree a) where
readsPrec d r = readParen (d > app_prec)
(\r -> [(Leaf m,t) |
("Leaf",s) <- lex r,
(m,t) <- readsPrec (app_prec+1) s]) r
++ readParen (d > up_prec)
(\r -> [(u:^:v,w) |
(u,s) <- readsPrec (up_prec+1) r,
(":^:",t) <- lex s,
(v,w) <- readsPrec (up_prec+1) t]) r
where app_prec = 10
up_prec = 5
(显然对于Tree
数据类型,但类似的规则适用于其他用户定义的ADT)。 (另外,上面是一个小小的谎言:GHC实际上使用了不同的实现,但除非你愿意在GHC内部挖掘,否则上面是你应该做的事情。)
read
是根据readsPrec
和readList
(Read
中的另一种方法定义的,除Char
之外的所有类型都默认使用[Char]
将Char
读作字符串而不是Int
列表。
如果标准派生不够,对于像你这样只是Read
的桶的类型,你可以忽略优先级参数。
BTW,Show
和{{1}}相当缓慢;您可能需要考虑使用其他方法对数据进行I / O.
答案 1 :(得分:3)
那是因为您可能想要实现的类方法是 readsPrec 。有关读取类型类的完整信息,请参阅此处:http://zvon.org/other/haskell/Outputprelude/Read_c.html
顺便说一句,你应该能够使用自动派生,编译器会为你实例化那些Read方法,例如:data Foo = Foo Int Int
deriving (Read, Show)