编写 fmap 时遇到问题

发布于 2024-08-14 08:50:54 字数 630 浏览 3 评论 0原文

我正在尝试为此类型编写一个 fmap

data Triangle a  = Triangle {t0 :: Point a, t1 ::  Point a, t2 ::  Point a}

,其中 Point 定义为

data Point a = Point {px :: a, py :: a, pz :: a}

我的实例 def 是

instance Functor Triangle where 
    fmap f (Triangle v0 v1 v2) = Triangle (f v0) (f v1) (f v2)

我收到以下编译错误,我无法弄清楚为什么

 C:\Scripts\Haskell\Geometry.hs:88:1:
     Occurs check: cannot construct the infinite type: a = Point a
     When generalising the type(s) for `fmap'
     In the instance declaration for `Functor Triangle'

有任何想法吗?

I am trying to write an fmap for this type

data Triangle a  = Triangle {t0 :: Point a, t1 ::  Point a, t2 ::  Point a}

where Point is defined as

data Point a = Point {px :: a, py :: a, pz :: a}

And my instance def is

instance Functor Triangle where 
    fmap f (Triangle v0 v1 v2) = Triangle (f v0) (f v1) (f v2)

I am getting the following compliation error and I can't figure out why

 C:\Scripts\Haskell\Geometry.hs:88:1:
     Occurs check: cannot construct the infinite type: a = Point a
     When generalising the type(s) for `fmap'
     In the instance declaration for `Functor Triangle'

Any ideas?

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

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

发布评论

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

评论(3

活泼老夫 2024-08-21 08:50:55

前面的答案为您提供了正确的解决方案,但更明确地了解这里发生的情况可能会有所帮助。 fmap 的类型为

fmap :: Functor f => (a -> b) -> f a -> f b

因此,instance 声明的类型推断按如下方式进行:

  1. fmap f (Triangle v0 v1 v2) 中,f 必须具有某种类型 a -> b(Triangle v0 v1 v2) 必须具有类型 Triangle a
    • 根据 Triangle 的定义,v0v1v2 必须具有类型 Point一个
    • 由于 f 应用于 v0v1v2,因此其参数类型 a 必须是Point a
    • 糟糕,a = a 点无法满足。

为什么定义三角形 (fmap f v0) (fmap f v1) (fmap f v2) 有效? :

  1. fmap f (Triangle v0 v1 v2) 中,f 必须具有某种类型 a ->; b(Triangle v0 v1 v2) 必须具有类型 Triangle a
    • 根据 Triangle 的定义,v0v1v2 必须具有类型 Point一个
    • 假设 PointFunctor 的实例,如上所述,fmap f v0 必须具有类型 Point b ,其中 bf 的结果类型。 v1v2 也是如此。
    • 因此Triangle (fmap f v0) (fmap f v1) (fmap f v2) 的类型为Triangle b
    • QED。

The previous answer gives you a correct solution, but it might be helpful to be more explicit about what's going on here. The type of fmap is

fmap :: Functor f => (a -> b) -> f a -> f b

So the type inference for your instance declaration proceeds as follows:

  1. In fmap f (Triangle v0 v1 v2), f must have some type a -> b and (Triangle v0 v1 v2) must have type Triangle a.
    • By the definition of Triangle, v0, v1, and v2 must have type Point a.
    • Since f is applied to v0, v1, and v2, its argument type a must be Point a.
    • Oops, a = Point a is unsatisfiable.

Why does the definition Triangle (fmap f v0) (fmap f v1) (fmap f v2) work? :

  1. In fmap f (Triangle v0 v1 v2), f must have some type a -> b and (Triangle v0 v1 v2) must have type Triangle a.
    • By the definition of Triangle, v0, v1, and v2 must have type Point a.
    • Assuming Point is an instance of Functor, as above, fmap f v0 must have type Point b, where b is the result type of f. Likewise for v1 and v2.
    • Hence Triangle (fmap f v0) (fmap f v1) (fmap f v2) has type Triangle b.
    • QED.
乄_柒ぐ汐 2024-08-21 08:50:55

顺便说一句,Functor 的一个有趣的属性是,只有一个可能的实例可以满足 函子定律

更好的是,可以使用 derive 包:

{-# LANGUAGE TemplateHaskell #-}

import Data.DeriveTH (derive, makeFunctor)

data Point a = Point {px :: a, py :: a, pz :: a}
$(derive makeFunctor ''Point)

data Triangle a  = Triangle {t0 :: Point a, t1 ::  Point a, t2 ::  Point a}
$(derive makeFunctor ''Triangle)

恕我直言,这部分是一个胜利,因为如果您决定更改 Triangle 的定义,它的 Functor 实例会自动为您维护。

Btw, an interesting property of Functor is that there is only one possible instance to make that will satisfy the Functor laws.

Better yet, this instance can be automatically produced for you using the derive package:

{-# LANGUAGE TemplateHaskell #-}

import Data.DeriveTH (derive, makeFunctor)

data Point a = Point {px :: a, py :: a, pz :: a}
$(derive makeFunctor ''Point)

data Triangle a  = Triangle {t0 :: Point a, t1 ::  Point a, t2 ::  Point a}
$(derive makeFunctor ''Triangle)

Imho this is a win partially because if you decide to change the definition of Triangle, its Functor instance is maintained automatically for you.

旧时光的容颜 2024-08-21 08:50:54
instance Functor Point where
    fmap f (Point v0 v1 v2) = Point (f v0) (f v1) (f v2)

instance Functor Triangle where
    fmap f (Triangle v0 v1 v2) = Triangle (fmap f v0) (fmap f v1) (fmap f v2)

在 Triangle 实例中,fa -> b.。我们必须将其转换为 Point a ->首先点b。然后我们可以让fmap f三角形a变换为三角形b。 (如果我正确理解你的意图,请观察你正在将 f 应用于 9 个对象)[编辑:是 27]

instance Functor Point where
    fmap f (Point v0 v1 v2) = Point (f v0) (f v1) (f v2)

instance Functor Triangle where
    fmap f (Triangle v0 v1 v2) = Triangle (fmap f v0) (fmap f v1) (fmap f v2)

In the Triangle instance, f is a -> b. We have to convert it to Point a -> Point b first. Then we can make fmap f transform Triangle a to Triangle b. (Observe you're applying f to 9 objects, if I understood your intention correctly) [edit: was 27]

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