2

我正在尝试为这种类型编写 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:
     发生检查:无法构造无限类型:a = Point a
     概括“fmap”的类型时
     在 `Functor Triangle' 的实例声明中

有任何想法吗?

4

3 回答 3

8
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)

在三角形实例中,fa -> b。我们必须将其转换为Point a -> Point b第一个。然后我们可以fmap f转换Triangle aTriangle b. (如果我正确理解您的意图,请注意您正在申请f9 个对象)[编辑:27 岁]

于 2009-12-15T22:42:16.873 回答
8

上一个答案为您提供了正确的解决方案,但更明确地了解这里发生的事情可能会有所帮助。的类型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,必须有 type 。v0v1v2Point a
    • 由于f应用于v0, v1, 和v2, 它的参数类型a必须是Point a.
    • 糟糕,a = Point a无法满足。

为什么定义Triangle (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,必须有 type 。v0v1v2Point a
    • 假设Point是 的实例Functor,如上所述,fmap f v0必须具有类型Point b,其中b是 的结果类型f。对于v1和 也是如此v2
    • 因此Triangle (fmap f v0) (fmap f v1) (fmap f v2)有类型Triangle b
    • QED。
于 2009-12-16T03:22:46.597 回答
2

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

更好的是,可以使用派生包自动为您生成此实例:

{-# 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实例会自动为您维护。

于 2009-12-17T11:16:01.573 回答