在Haskell中为自定义数据类型创建Read类的实例

时间:2011-04-02 03:36:56

标签: haskell typeclass

我有自定义数据类型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'

有人可以告诉我问题是什么以及我如何实际实例化这种类型?

2 个答案:

答案 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是根据readsPrecreadListRead中的另一种方法定义的,除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)