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

发布于 2024-12-09 12:47:04 字数 657 浏览 0 评论 0原文

给定一个类型类:

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

谢谢

Given a 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)

And an instance:

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

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

How can I write another function (somewhere else) that calls the feed function defined in the typeclass? Example:

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

Thanks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

﹉夏雨初晴づ 2024-12-16 12:47:04

问题是 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

The problem is that Haskell can't figure out what type you want to use for food. It sees one instance:

instance AnimalTrainer Animal Food

But maybe there is a second instance somewhere...

instance AnimalTrainer Animal Poison

So you need to tell Haskell that animals get food only, and not something else like poison.

Solution 1: You can use functional dependencies:

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

This tells Haskell that for each animal type, there is only one food type that it will eat.

Solution 2: You can also use type families.

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)

I personally consider this solution a little more esoteric, and the syntax a little less natural. But the example is contrived, so I include this for completeness.

Solution 3: You could add explicit type annotations whenever you call feed.

feedEverything = snd ((feed :: Animal -> (Food, Int)) Dog) == 0
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文