Haskell类定义中的隐式类型参数?

时间:2010-07-14 07:50:59

标签: haskell type-inference typeclass

通常以下情况似乎是非法的:

class Foo a where
    foo :: a -> b -> a

哪个有意义;我们怎么知道b是什么?

但是,如果我们看看Functor的定义:

class Functor f where
    fmap :: (a -> b) -> f a -> f b

我们看到ab出现,即使我们只指定f作为类型变量。我猜这是允许的,因为编译器看到例如f a并且可以确定f本身必须采用a,因此在Functor定义中的其他地方使用a是安全的。我是对的吗?

2 个答案:

答案 0 :(得分:6)

让我们分别看一下每一行。

class Functor f where

这声明了一个名为Functor的单参数类型类;满足它的类型将被称为f

  fmap :: (a -> b) -> f a -> f b

与任何函数定义一样,所有自由类型变量都隐式forall - 它们可以被任何东西替换。但是,由于第一行,f在范围内。因此,fmap具有类型签名fmap :: forall a b. Functor f => (a -> b) -> f a -> f b。换句话说,每个仿函数都需要有一个fmap的定义,它可以用于任何 ab,而f必须有< strong> kind (类型的类型)* -> *;也就是说,它必须是采用其他类型的类型,例如[]MaybeIO

你说的话是不正确的; a并不特殊,如果我们在Functor中有另一个功能,则看不到相同的ab。但是,编译器 使用f a位来确定f必须是什么类型。此外,您的Foo课程完全合法;我可以指定一个实例如下

instance Foo (a -> b) where
  foo f _ = f

这符合{em>任何 foo :: a -> b -> a的{​​{1}};请注意b中的b不同。不可否认,这不是一个非常有趣的例子,但它完全合法。

答案 1 :(得分:3)

它不需要“知道”。它只需要进行类型检查(即未能进行类型检查)。 b可以是任何东西;函数foo必须能够将任何类型作为第二个参数。

考虑前奏中的const函数:

const            :: a -> b -> a
const x _        =  x

它如何“知道”b(或a就此而言)是什么?