给出一个类型类:
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
由于
答案 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