何时在Haskell中使用Multiparameter类型?

时间:2014-04-27 08:25:53

标签: haskell typeclass

我想了解Collection类型的以下两个定义之间的区别。

使用多参数类型类和函数依赖项(取自here);

{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, FunctionalDependencies #-}

class Eq e => Collection c e | c -> e where
    insert :: c -> e -> c
    member :: c -> e -> Bool

instance Eq a => Collection [a] a where
    insert = flip (:)
    member = flip elem

只有一个类型参数;

class Collection c where
    insert :: Eq e => c e -> e -> c e
    member :: Eq e => c e -> e -> Bool

instance Collection [] where
    insert = flip (:)
    member = flip elem

两者似乎都可以编译并正常工作。这两者之间是否有任何实际差异,或任何理由支持一种方法而不是另一种方法?

2 个答案:

答案 0 :(得分:5)

一个简单的例子,Fundep版本仍然有效,但不是单参数版本,是a Set container

import qualified Data.Set as Set

instance (Ord e) => Collection (Set.Set e) e where
  insert = Set.insert
  member = flip Set.member

另一个类的实例不起作用,因为您需要Ord约束。现在,您可以将定义更改为

class Collection c where
    insert :: Ord e => c e -> e -> c e
    member :: Ord e => c e -> e -> Bool

但是对于像列表这样只会令人讨厌的简单容器,您还希望在那里存储非ord类型。对于Hashmaps,您还需要另一个约束。 任何集合都需要这些全局和必需品。

答案 1 :(得分:4)

你的第二个变种的另一个用例是单形容器。例如,ByteString可以被视为Char的容器。

还应该注意的是,存在基于类型族的第三种替代方案,其是最灵活的类型。虽然在这个琐碎的案例中,它与基于fundeps的游戏没有多大区别。

{-# LANGUAGE TypeFamilies #-}

import qualified Data.ByteString.Char8 as B

class Collection c where
  type Row c
  insert :: c -> Row c -> c
  member :: c -> Row c -> Bool

instance (Eq a) => Collection [a] where
  type Row [a] = a
  insert = flip (:)
  member = flip elem

instance Collection B.ByteString where
  type Row B.ByteString = Char
  insert = flip B.cons
  member = flip B.elem