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

J C*_*per 4 haskell type-inference typeclass

通常看来以下是非法的:

class Foo a where
    foo :: a -> b -> a
Run Code Online (Sandbox Code Playgroud)

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

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

class Functor f where
    fmap :: (a -> b) -> f a -> f b
Run Code Online (Sandbox Code Playgroud)

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

Ant*_*sky 6

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

class Functor f where
Run Code Online (Sandbox Code Playgroud)

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

  fmap :: (a -> b) -> f a -> f b
Run Code Online (Sandbox Code Playgroud)

像任何函数定义一样,所有自由类型变量都是隐式forall编辑的 - 它们可以被任何东西替换.但是,由于第一行,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
Run Code Online (Sandbox Code Playgroud)

这满足foo :: a -> b -> a所有 b ; 请注意,bin Foo (a -> b)是不同的.不可否认,这不是一个非常有趣的例子,但它完全合法.