Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell-调用typeclass中定义的函数_Haskell - Fatal编程技术网

Haskell-调用typeclass中定义的函数

Haskell-调用typeclass中定义的函数,haskell,Haskell,给定一个typeclass: 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 imple

给定一个typeclass:

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)
instance AnimalTrainer Animal Food
如何编写另一个调用typeclass中定义的feed函数的函数(在其他地方)?例如:

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

谢谢

问题是哈斯克尔不知道你想用什么类型的食物。它看到一个例子:

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

instance AnimalTrainer Animal Food where
    getFood Dog = (Meat, 2)
    getFood Cat = (Milk, 3)
instance AnimalTrainer Animal Food
但也许还有第二个例子

instance AnimalTrainer Animal Poison
所以你需要告诉哈斯克尔,动物只吃东西,而不是像毒药这样的东西

解决方案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:您可以在调用提要时添加显式类型注释

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

顺便说一句,你必须在你的文件中添加一个pragma来实现这一点:
{-#语言功能依赖性#-}
@fuzzxl:我忽略了这一点,因为这不是一个完整的模块,海报的代码没有扩展也无法编译。非常感谢。另一个疑问是,假设我不能修改typeclass声明(由第三方提供)。是否可以通过修改调用站点(feedEverything)使feed的函数调用工作?@Gabriel:是的,这也是可能的。我添加了第三种解决方案。有时很难用人为的例子来解释,因为“狗”、“饲料”和“肉”这样的词听起来很相关,但实际上并不相关。将来,如果你使用诸如X、Y、Z、f、g等名称,回答这个问题可能会更容易。我知道你的意思,当我看到他们的代码并试图回答他们的问题时,我有时会努力找出人们真正想要或需要什么(关于其他语言,而不是Haskell,显然我才刚刚开始学习)。因此,我认为最好给出一些上下文,而不是使用(对我来说)没有任何意义的简单字母。我想最好的方法是使用实际问题,而不是试图想出类似的东西,这几乎肯定是人为的。顺便说一句,你的答案很好:既完整又结构良好。再次感谢你的帮助。