Haskell 类型类实例中的统一怪诞

Haskell 类型类实例中的统一怪诞,haskell,functional-programming,typeclass,unification,type-theory,Haskell,Functional Programming,Typeclass,Unification,Type Theory,假设我有以下(愚蠢的)课程: 我可以提供以下[]实例: instance BlindMap [] where mapB = map id RHS的类型为[a]->[a],应与[a]->[b]统一,但GHC不这么认为: Couldn't match type ‘a’ with ‘b’ ‘a’ is a rigid type variable bound by the type signature for mapB :: [a] -> [b] at dingas.hs

假设我有以下(愚蠢的)课程:

我可以提供以下
[]
实例:

instance BlindMap [] where
    mapB = map id
RHS的类型为
[a]->[a]
,应与
[a]->[b]
统一,但GHC不这么认为:

Couldn't match type ‘a’ with ‘b’
  ‘a’ is a rigid type variable bound by
      the type signature for mapB :: [a] -> [b] at dingas.hs:11:5
  ‘b’ is a rigid type variable bound by
      the type signature for mapB :: [a] -> [b] at dingas.hs:11:5
Expected type: a -> b
  Actual type: b -> b
Relevant bindings include
  mapB :: [a] -> [b]
In the first argument of ‘map’, namely ‘id’
In the expression: map id
我错过了什么

提前谢谢

我错过了什么

map id
在给定某个值列表的情况下,生成一个任意类型的值列表<代码>[a]->[b]承诺在给定可能不同类型的值列表的情况下,生成某种任意类型的值列表


因此,它所期望的是
a->b
,但基于id的函数只能获取它返回的内容,因此
b->b

更一般地说,您说您将提供类型为:

forall a b.[a] -> [b]
在实例定义中。编译器相信了你的话

现在,您提出了一个实例,编译器真的需要看到这个神奇的函数。而且它拒绝所有做得比你承诺的少的代码

在继续之前,您应该尝试编写一个函数

forall a b. a -> b
您将看到,您最多可以想出以下方法:

f x = f x
g x = error "not terminating."
只要没有可用的元素映射函数,就只能编写以下实例:

instance BlindMap (Maybe a) where mapB _ = Nothing
instance BlindMap ([a])     where mapB _ = []

以同样的精神等等

可能不同,但不一定不同。实例声明中
mapB
的具体类型是
[a]->[a]
。让
m~[]
因为这是我们所在实例的主体,
[a]->[a]
通过让
a~b
[a]->[b]
统一。其他示例包括
map::(a->b)->[a]->[b]
<代码>地图id::[a]->[a],在GHCi
:t[undefined::a->b,undefined a->a]
中,产生了
[undefined::a->b,undefined a->a]:[b->b]
@TWhit,你混淆了这两个例子。在您的例子中,
id
函数使映射的类型更加具体,但这是因为我们在函数之外,并且正在利用它的一种可能的具体化。它的内部仍然必须以允许
a
b
不同的方式实现。你所做的是实现你的函数,而不是使用它,因此你上面写的是不正确的,因为有人可能想在
a~/~b
的上下文中使用你的类;在类实例中,我不允许具体化类定义中规定的类型。简而言之,
[a]->[a]
[a]->[b]
确实是统一的;但在这里,统一不是利益的运作。相反,兴趣的操作是类型检查;“这个术语可以被赋予这种类型吗?”
MapID
不能被赋予类型
[a]->[b]
——你相信这一点,还是这也是混淆的一部分?是的,我没有意识到方法实现的类型必须与类规定的类型完全相同,而不仅仅是统一的。@TWhit哦,这也不太准确;例如,可以给出一个方法定义,其推断类型比实例所需的类型更一般。(也有其他例外。)但是,是的,这是基本思想。如果说方法定义的推断类型可能不会进一步具体化w.r.t.类的“规定类型”是否准确?@TWhit我认为谈论定义的推断类型是误导性的。相反,正确的说法是定义可以被赋予类指定的类型。完全有可能给出一个类型无法推断(甚至没有最通用的类型)但被编译器接受的方法定义——因此真正的标准是关于类型检查,而不是类型推断。
instance BlindMap (Maybe a) where mapB _ = Nothing
instance BlindMap ([a])     where mapB _ = []