Давайте посмотрим на каждую строку отдельно.
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
, которое может работать для любых a
и b
, а f
должно иметь kind (типтипа) * -> *
;то есть это должен быть тип, который принимает другой тип, такой как []
или Maybe
или IO
.
То, что вы сказали, неверно;a
не является особенным, и если бы у нас была другая функция в Functor
, она бы не увидела тот же a
или b
.Однако компилятор использует бит f a
, чтобы выяснить, каким должен быть тип f
.Кроме того, ваш Foo
класс совершенно легален;Я мог бы указать экземпляр следующим образом:
instance Foo (a -> b) where
foo f _ = f
Это удовлетворяет foo :: a -> b -> a
для any b
;обратите внимание, что b
в Foo (a -> b)
отличается.По общему признанию, это не очень интересный случай, но это совершенно законно.