Haskell - 调用类型类中定义的函数

时间:2011-10-10 22:26:20

标签: haskell

给出一个类型类:

class AnimalTrainer animal food where
    getFood :: animal -> (food, Int) -- Returns the food and the quantity
    feed :: animal -> (food, Int) -- Returns the leftovers

    feed a = feed' (getFood a) -- Provide a default implementation
        where feed' (f, n) = (f, n - 1)

一个例子:

data Animal = Dog | Cat
data Food = Meat | Milk

instance AnimalTrainer Animal Food where
    getFood Dog = (Meat, 2)
    getFood Cat = (Milk, 3)

如何编写调用类型类中定义的feed函数的另一个函数(在其他地方)?例如:

feedEverything :: Bool
feedEverything = snd (feed Dog) == 0

由于

1 个答案:

答案 0 :(得分:10)

问题在于Haskell无法确定您想要用于食物的类型。它看到一个例子:

instance AnimalTrainer Animal Food

但也许在某个地方有第二个实例......

instance AnimalTrainer Animal Poison

所以你需要告诉Haskell动物只能获得食物,而不是像毒药一样的食物。

解决方案1:您可以使用功能依赖项:

class AnimalTrainer animal food | animal -> food where
    ...

这告诉Haskell,对于每种动物类型,它只会吃一种食物类型。

解决方案2:您还可以使用类型系列。

class AnimalTrainer animal where
    type AnimalFood animal :: *
    getFood :: animal -> (AnimalFood animal, Int)
    feed :: animal -> (AnimalFood animal, Int)

    feed a = feed' (getFood a) -- Provide a default implementation
        where feed' (f, n) = (f, n - 1)

data Animal = Dog | Cat
data Food = Meat | Milk

instance AnimalTrainer Animal where
    type AnimalFood Animal = Food
    getFood Dog = (Meat, 2)
    getFood Cat = (Milk, 3)

我个人认为这个解决方案更加深奥,语法不那么自然。但是这个例子是人为的,所以我把它包括在内是为了完整性。

解决方案3 :每当您调用Feed时,都可以添加显式类型注释。

feedEverything = snd ((feed :: Animal -> (Food, Int)) Dog) == 0