2010-07-14 67 views
4

它通常似乎以下是非法的:Haskell类定义中的隐式类型参数?

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

这是合理的;我们怎么知道b是什么?

但是,如果我们看一下仿函数的定义:

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

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

回答

6

让我们分别看看每条线。

class Functor f where 

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

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

像任何函数定义,所有空闲类型变量隐含forall ED-他们可以和任何被替换。但是,由于第一行,f在范围内。因此,fmap的类型签名为fmap :: forall a b. Functor f => (a -> b) -> f a -> f b。换句话说,每一个函子需要具有fmap定义它可以为任何ab,并f工作必须(一种类型)* -> *;也就是说,它必须是另一种类型,例如[]MaybeIO

那么你说什么是不正确的; a不是特别的,如果我们在Functor中有另一个功能,它将看不到相同的ab。然而,编译器确实使用f a位来找出什么样的f必须是。此外,您的Foo类完全合法;我可以按如下

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

这满足foo :: a -> b -> a任何b指定实例;请注意0​​中的b是不同的。诚然,这不是一个非常有趣的例子,但它是完全合法的。

3

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

考虑const功能从前奏:

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

它是如何 “知道” 什么b(或a,对于这个问题)是什么?