【问题标题】:Creating instance of Read type class in Haskell for custom data type在 Haskell 中为自定义数据类型创建读取类型类的实例
【发布时间】:2011-04-02 03:36:56
【问题描述】:

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

谁能告诉我问题出在哪里以及我如何才能实际实例化这种类型?

【问题讨论】:

    标签: haskell typeclass


    【解决方案1】:

    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 是根据readsPrecreadList 定义的(Read 中的另一种方法,除了Char 用于将[Char] 读取为字符串而不是作为Char 的列表)。

    如果标准推导不够,对于像您这样的类型,它只是 Ints 的桶,您可以忽略优先级参数。

    顺便说一句,ReadShow 相当慢;您可能需要考虑使用其他方式对您的数据进行 I/O。

    【讨论】:

    • 您对阅读和展示的替代方案有什么建议吗?
    【解决方案2】:

    那是因为您可能想要实现的类方法是 readsPrec。有关读取类型类的完整信息,请参见此处:http://zvon.org/other/haskell/Outputprelude/Read_c.html

    顺便说一句,您应该能够只使用自动派生,编译器将为您实例化这些 Read 方法,例如:

    data Foo = Foo Int Int
               deriving (Read, Show)
    

    【讨论】:

    • 我知道我可以做到,但我不太喜欢自动完成读取的方式,因为它不太直观并且想要制作更好的版本。
    猜你喜欢
    • 2017-04-03
    • 1970-01-01
    • 2015-02-03
    • 1970-01-01
    • 1970-01-01
    • 2013-11-25
    • 1970-01-01
    • 2016-12-05
    • 2013-03-29
    相关资源
    最近更新 更多