Bifunctor实例定义上的类型签名不匹配 [英] Type Signature Mismatch on Bifunctor instance definition

查看:43
本文介绍了Bifunctor实例定义上的类型签名不匹配的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我通过阅读《第一原理》中的Haskell编程来学习Haskell,Allen&森之喜.

在有关Monad变压器的章节中,Functor&适用的组合,它要求读者为以下类型编写Bifunctor实例

In the exercises for the chapter on Monad Transformers, Functor & Applicative composition, it asks the reader to write Bifunctor instance for the following type

data SemiDrei a b c = SemiDrei a

我的第一次尝试(编译)是

My first attempt (which compiles) was

instance Bifunctor (SemiDrei a) where
    bimap f g (SemiDrei a) = SemiDrei a

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

But, looking at it, It seemed to me that I ought to be able to write bimap f g = id because the last argument is yielded unchanged or write bimap f g x = x. Both gave me compile errors, and I'm hoping someone can explain to me why I can't express the bimap with these shorter alternatives, i.e. why do I have to specify (SemiDrei a).

我在Haskell 8.6.5上运行了此命令(如果相关)

I ran this on Haskell 8.6.5 (in case that is relevant)

尝试: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->p g :: y->q .

There last argument is not, in fact, yielded unchanged: its type changes. The input is SemiDrei a x y and the output is SemiDrei a p q, where f :: x -> p and g :: y -> q.

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

This means that you have to deconstruct the value of the original type and reconstruct a value of the new type, which is what you're doing in the original implementation.

但是您的直觉是正确的:这两个值确实具有相同的内存表示形式.GHC可以推断出这一事实,当它发生时,它将自动解决

But your intuition is correct: the two values do have the same in-memory representation. And GHC can deduce this fact, and when it does, it will automatically solve a Coercible constraint for you, which means that you can use the coerce function to convert one to the other:

 bimap _ _ = coerce

这篇关于Bifunctor实例定义上的类型签名不匹配的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆