2

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

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

以下代码是我想出的,但它不起作用:你将如何解决它?

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                       

提前致谢!

4

3 回答 3

12

与其定义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
于 2012-07-10T14:29:57.153 回答
7

你可以

  • 使其成为构造函数类,

    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
    

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

于 2012-07-10T14:33:49.507 回答
3

对列表进行抽象的最简单方法是对类型构造函数进行抽象,即 over [],而不是 over [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
于 2012-07-10T14:31:01.207 回答