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

use*_*261 21 haskell typeclass

我有一个自定义数据类型Foo = Foo{ a :: Int, b :: Int},我正在尝试使Foo成为自定义读取实例.我已经有了一个功能bar :: String -> Foo,我尝试这样做:

instance Read (Foo a b) where
    read s = bar s
Run Code Online (Sandbox Code Playgroud)

但是当我将文件加载到GHCi中进行测试时,我收到以下错误: Fraction.hs:11:1: read' is not a (visible) method of class Read'

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

gee*_*aur 18

阅读类型类没有声明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
Run Code Online (Sandbox Code Playgroud)

(这显然对于Tree数据类型,但类似的规则适用于其他用户定义的ADT).(另外,上面是一个小小的谎言:GHC实际上使用了不同的实现,但除非你愿意在GHC里面挖掘,否则上面是你应该做的事情.)

read是根据readsPrec和定义的readList(另一种方法Read,对于每种类型都是默认的,除非Char它用来读[Char]作字符串而不是列表Char).

如果标准派生是不够的,对于像你这样的类型只是一个桶的Ints,你可以忽略优先级参数.

BTW,Read而且Show相当缓慢; 您可能需要考虑使用其他方法对数据执行I/O操作.

  • 你对阅读和展示的替代品有什么建议吗? (14认同)