在Functor实例声明中

kjo*_*kjo 7 haskell

这加载没有错误:

data Const c a = Const c

instance Functor (Const c) where
    fmap _ (Const v) = Const v
Run Code Online (Sandbox Code Playgroud)

...但是这个

data Const' c a = Const' c

instance Functor (Const' c) where
    fmap _ cv = cv
Run Code Online (Sandbox Code Playgroud)

......失败了:

    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)'
Run Code Online (Sandbox Code Playgroud)

我不明白这个错误.为什么不能编译器推断类型cvConst' c?鉴于声明的其余部分以及fmap?的定义,还有什么呢?

luq*_*qui 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
Run Code Online (Sandbox Code Playgroud)

这有点拗口.:-)

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

  • 你确定`c`应该在那里量化吗?在我看来,`c`应该是由实例头隐式绑定的那个. (2认同)
  • 你是对的.我在最后一刻对c进行了量化,但这是不正确的.固定 (2认同)

Rei*_*chs 7

cv是类型Const' c a,所以它也不能是类型Const' c b(除非a ~ b).Const v并且Const v,但是,可以是不同类型的.

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