haskell - Bifunctor 实例定义上的类型签名不匹配

标签 haskell types bifunctor

我正在通过阅读本书来了解 Haskell Haskell Programming from First Principles, Allen & Moronuki .

在 Monad Transformers, Functor & Applicative composition 一章的练习中,它要求读者为以下类型编写 Bifunctor 实例

data SemiDrei a b c = SemiDrei a

我的第一次尝试(编译)是
instance Bifunctor (SemiDrei a) where
    bimap f g (SemiDrei a) = SemiDrei a

但是,看着它,我觉得我应该可以写bimap f g = id因为最后一个参数不变或写 bimap f g x = x .两者都给了我编译错误,我希望有人可以向我解释为什么我不能表达 bimap使用这些较短的替代方案,即为什么我必须指定 (SemiDrei a) .

我在 Haskell 8.6.5 上运行了这个(如果相关的话)

尝试:id
instance Bifunctor (SemiDrei a) where
    bimap f g = id

-- compile error message:
• Couldn't match type ‘a1’ with ‘b’
  ‘a1’ is a rigid type variable bound by
    the type signature for:
      bimap :: forall a1 b c d.
               (a1 -> b) -> (c -> d) -> SemiDrei a a1 c -> SemiDrei a b d
    at src/Main.hs:69:5-9
  ‘b’ is a rigid type variable bound by
    the type signature for:
      bimap :: forall a1 b c d.
               (a1 -> b) -> (c -> d) -> SemiDrei a a1 c -> SemiDrei a b d
    at src/Main.hs:69:5-9
  Expected type: SemiDrei a a1 c -> SemiDrei a b d
    Actual type: SemiDrei a b d -> SemiDrei a b d
• In the expression: id
  In an equation for ‘bimap’: bimap f g = id
  In the instance declaration for ‘Bifunctor (SemiDrei a)’
• Relevant bindings include
    f :: a1 -> b (bound at src/Main.hs:69:11)
    bimap :: (a1 -> b) -> (c -> d) -> SemiDrei a a1 c -> SemiDrei a b d
      (bound at src/Main.hs:69:5)
   |
69 |     bimap f g = id
   |                 ^^

尝试:f g x = x
instance Bifunctor (SemiDrei a) where
    bimap f g x = x

-- compile error message:
• Couldn't match type ‘a1’ with ‘b’
  ‘a1’ is a rigid type variable bound by
    the type signature for:
      bimap :: forall a1 b c d.
               (a1 -> b) -> (c -> d) -> SemiDrei a a1 c -> SemiDrei a b d
    at src/Main.hs:69:5-9
  ‘b’ is a rigid type variable bound by
    the type signature for:
      bimap :: forall a1 b c d.
               (a1 -> b) -> (c -> d) -> SemiDrei a a1 c -> SemiDrei a b d
    at src/Main.hs:69:5-9
  Expected type: SemiDrei a b d
    Actual type: SemiDrei a a1 c
• In the expression: x
  In an equation for ‘bimap’: bimap f g x = x
  In the instance declaration for ‘Bifunctor (SemiDrei a)’
• Relevant bindings include
    x :: SemiDrei a a1 c (bound at src/Main.hs:69:15)
    f :: a1 -> b (bound at src/Main.hs:69:11)
    bimap :: (a1 -> b) -> (c -> d) -> SemiDrei a a1 c -> SemiDrei a b d
      (bound at src/Main.hs:69:5)
   |
69 |     bimap f g x = x
   |                   ^

最佳答案

事实上,最后一个参数并没有保持不变:它的类型发生了变化。输入是 SemiDrei a x y输出为 SemiDrei a p q ,其中 f :: x -> pg :: y -> q .

这意味着您必须解构原始类型的值并重建新类型的值,这就是您在原始实现中所做的。

但是您的直觉是正确的:这两个值确实具有相同的内存表示。而 GHC 可以推导出这个事实,当它推导出来时,它会自动解决一个 Coercible 对您的约束,这意味着您可以使用 coerce将一个转换为另一个的函数:

 bimap _ _ = coerce

关于haskell - Bifunctor 实例定义上的类型签名不匹配,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58494308/

相关文章:

python - 在 Pandas 的同一系列中获取不同的数据类型

scala - Hom Functor 的逆变和Scala 的Function1 之间有什么联系吗?

haskell - 代表性双仿函数的不动点

Haskell 类型级别文字 Nat : status?

haskell - 如何将失败的计算转换为成功的计算,反之亦然

c++ - 如何在 C++ 中引用函数(转换 python 代码)

go - 类型更改未按预期运行

haskell - 当用作多种类型的值时,如何处理这个多态值?

haskell - 阐明列表单子(monad)运算符的作用