在Functor实例声明

时间:2015-09-17 23:19:40

标签: haskell

加载时没有错误:

data Const c a = Const c

instance Functor (Const c) where
    fmap _ (Const v) = Const v

......但是这个

data Const' c a = Const' c

instance Functor (Const' c) where
    fmap _ cv = cv

...失败了:

    Couldn't match type `a' with `b'
      `a' is a rigid type variable bound by
          the type signature for fmap :: (a -> b) -> Const' c a -> Const' c b
          at test.hs:4:5
      `b' is a rigid type variable bound by
          the type signature for fmap :: (a -> b) -> Const' c a -> Const' c b
          at test.hs:4:5
    Expected type: Const' c b
      Actual type: Const' c a
    In the expression: cv
    In an equation for `fmap': fmap _ cv = cv
    In the instance declaration for `Functor (Const' c)'

我不明白这个错误。为什么编译器不能推断出cv的类型是Const' c?鉴于声明的其余部分以及fmap的定义?

,还有什么可能呢?

2 个答案:

答案 0 :(得分:9)

如果你想要完全明确,你可以写

{-# LANGUAGE ScopedTypeVariables, InstanceSigs #-}

data Const c a = Const c

instance Functor (Const c) where
    fmap :: forall a b. (a -> b) -> Const c a -> Const c b
    fmap _ (Const v :: Const c a) = Const v :: Const c b

哪个有点满口。 : - )

forall a b.ab纳入范围,以便在定义中引用它们。这由ScopedTypeVariables启用。 InstanceSigs允许我们首先编写fmap的签名(通常必须从类中推断出来,因此我们无处可从中获取类型变量名称)

答案 1 :(得分:7)

cv属于Const' c a类型,因此它也不能属于Const' c b类型(除非a ~ b)。但是,Const vConst v可以是不同类型的。

另一种看待它的方式是fmap _ cv = cv等同于fmap _ = id,其类型为Const' c a -> Const' c a,但fmap _必须属于Const' c a -> Const' c b类型}。