通常以下情况似乎是非法的:
class Foo a where
foo :: a -> b -> a
哪个有意义;我们怎么知道b
是什么?
但是,如果我们看看Functor的定义:
class Functor f where
fmap :: (a -> b) -> f a -> f b
我们看到a
和b
出现,即使我们只指定f
作为类型变量。我猜这是允许的,因为编译器看到例如f a
并且可以确定f
本身必须采用a
,因此在Functor定义中的其他地方使用a
是安全的。我是对的吗?
答案 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
的定义,它可以用于任何 a
和b
,而f
必须有< strong> kind (类型的类型)* -> *
;也就是说,它必须是采用其他类型的类型,例如[]
或Maybe
或IO
。
你说的话是不正确的; a
并不特殊,如果我们在Functor
中有另一个功能,则看不到相同的a
或b
。但是,编译器 使用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
就此而言)是什么?