Haskell类定义中的隐式类型参数?
通常情况下,以下行为似乎是非法的:Haskell类定义中的隐式类型参数?,haskell,type-inference,typeclass,Haskell,Type Inference,Typeclass,通常情况下,以下行为似乎是非法的: class Foo a where foo :: a -> b -> a 这是有道理的;我们如何知道b是什么 但是,如果我们看函子的定义: class Functor f where fmap :: (a -> b) -> f a -> f b 我们看到出现了a和b,尽管我们只将f指定为类型变量。我猜这是允许的,因为编译器可以看到例如fa,并且可以计算出f本身必须取a,所以在我们的函子定义的其他地方使用a是安全
class Foo a where
foo :: a -> b -> a
这是有道理的;我们如何知道b
是什么
但是,如果我们看函子的定义:
class Functor f where
fmap :: (a -> b) -> f a -> f b
我们看到出现了a
和b
,尽管我们只将f
指定为类型变量。我猜这是允许的,因为编译器可以看到例如fa
,并且可以计算出f
本身必须取a
,所以在我们的函子定义的其他地方使用a
是安全的。我说的对吗?不需要“知道”。它只需要进行打字检查(即,不能不进行打字检查)b
可以是任何东西;函数foo
必须能够将任何类型作为第二个参数
考虑前奏曲中的const
函数:
const :: a -> b -> a
const x _ = x
它是如何“知道”什么是
b
(或者a
,就这一点而言)的呢?让我们分别看看每一行
class Functor f where
这声明了一个名为Functor
的单参数类型类;满足此条件的类型将被称为f
fmap :: (a -> b) -> f a -> f b
与任何函数定义一样,所有自由类型变量都是隐式的forall
ed,它们可以被任何东西替换。但是,多亏了第一行,f
在范围内。因此,fmap
具有类型签名fmap::forall a b。函子f=>(a->b)->f a->f b
。换句话说,每个函子都需要有一个fmap
的定义,它可以用于任何a
和b
,而f
必须有种类(类型的类型)*->*
;也就是说,它必须是采用另一种类型的类型,例如[]
或可能
或IO
那么,你所说的是不正确的;a
并不特殊,如果我们在Functor
中有另一个函数,它将不会看到相同的a
或b
。但是,编译器确实使用fa
位来确定f
必须是什么类型的。此外,你的Foo
课程是完全合法的;我可以如下指定一个实例
instance Foo (a -> b) where
foo f _ = f
这满足了任何b
的foo::a->b->a
;注意Foo(a->b)
中的b
是不同的。诚然,这不是一个很有趣的例子,但它是完全合法的