【问题标题】:User-defined List instance用户自定义 List 实例
【发布时间】:2012-07-10 01:20:03
【问题描述】:

这应该很简单,但我似乎无法绕过它。

假设我有自己的 List 类,在其接口中声明 headtailList 应该是您所期望的,即同质项目的集合。 然后,我想创建一个实现List 接口的data 类型。

以下代码是我想出的,但它不起作用:您将如何修复它?

class List l where                                                             
    head :: l -> a  -- ERROR! How do I tell: given a list, return an element?                                                      
    tail :: l -> l                                                             

data ConsList a = Nil | Cons a (ConsList a)                                    

instance List (ConsList Int) where                                             
    head Nil = error "Empty List"                                              
    head (Cons h _) = h                                                        
    tail Nil = error "Empty List"                                              
    tail (Cons _ t) = t                       

提前致谢!

【问题讨论】:

  • 只是一个元注释:Haskell 初学者经常声明类有点常见。你可能只想写两个head :: ConsList a -> atail :: ConsList a -> ConsList a 类型的函数,而不是一个类。
  • 作为一个更通用的“列表类”的示例,请考虑 parsec 的 Stream
  • @DanielWagner 我同意你的看法!我只是在阅读 Okasaki 的书,它解释了同一接口的许多实现,但我被这个问题困在第 3 页。

标签: class haskell types


【解决方案1】:

与其将List定义为一个类型类,不如将其定义为一个构造函数类:

class List l where
    head :: l a -> a
    tail :: l a -> l a                                        

data ConsList a = Nil | Cons a (ConsList a)

instance List ConsList where
    head Nil = error "Empty List"
    head (Cons h _) = h
    tail Nil = error "Empty List"
    tail (Cons _ t) = t

或者,修复元素类型(注意:对于您的类型ConsList,这需要灵活的实例):

{-# LANGUAGE FlexibleInstances #-}

class List l where
    head :: l -> Int
    tail :: l -> l

data ConsList a = Nil | Cons a (ConsList a)

instance List (ConsList Int) where
    head Nil = error "Empty List"
    head (Cons h _) = h
    tail Nil = error "Empty List"
    tail (Cons _ t) = t

最后,使用类型族,您可以做更多花哨的事情,但如果您应该走那么远(可能不会),这真的取决于您的具体情况:

{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE TypeFamilies      #-}

class List l where
    type Elt l
    head :: l -> Elt l
    tail :: l -> l

data ConsList a = Nil | Cons a (ConsList a)

instance List (ConsList Int) where
    type Elt (ConsList Int) = Int

    head Nil = error "Empty List"
    head (Cons h _) = h

    tail Nil = error "Empty List"
    tail (Cons _ t) = t

【讨论】:

  • 在你的第二个例子中 - 你有 head::l->Int 这是一个错字还是有意的,如果后者我不明白,它只能在整数列表上工作,或者我错过了一点。诚然,我还没有遇到flexible instances
  • @epsilon'εⳆ2'halbe 这是有意的。它修复了抽象到Int的列表的元素类型。
  • 但它只适用于List Int 和其他head 没有任何意义,所有漂亮的多态性都会消失,这对吗??
【解决方案2】:

对列表进行抽象的最简单方法是对类型构造函数进行抽象,即对[],而不是对[a](这是[] a 的语法糖)。

所以你的班级变成了:

class List l where
  head :: l a -> a  -- now l is applied to the element type
  tail :: l a -> l a

然后您的实例会相应更改:

instance List ConsList where
  ...  -- code as before

【讨论】:

    【解决方案3】:

    你可以

    • 使其成为构造函数类,

      class List l where
          head :: l a -> a
          tail :: l a -> l a
      
    • 使其成为具有功能依赖的多参数类型类

      class List l a | l -> a where
          head :: l -> a
          tail :: l -> l
      
    • 使用类型族

      class List l where
          type Elem l
          head :: l -> Elem l
          tail :: l -> l
      

    我认为构造函数类是最好的方法。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-05-30
      • 1970-01-01
      • 2011-12-24
      • 2016-05-04
      • 2013-08-28
      • 1970-01-01
      相关资源
      最近更新 更多