Неявные параметры типа в определении класса Haskell?

Обычно кажется незаконным следующее:

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, так что можно безопасно использовать этот a в другом месте нашего определения Functor. Я прав?


person J Cooper    schedule 14.07.2010    source источник


Ответы (2)


Рассмотрим каждую строку отдельно.

class Functor f where

Это объявляет класс типа с одним параметром, называемый Functor; тип, который ему удовлетворяет, будет называться f.

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

Как и любое определение функции, все переменные свободного типа неявно foralled — их можно заменить чем угодно. Однако, благодаря первой строке, 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 для любого b; обратите внимание, что b в Foo (a -> b) отличается. По общему признанию, это не очень интересный случай, но вполне законный.

person Antal Spector-Zabusky    schedule 14.07.2010

Не нужно «знать». Ему просто нужно проверить тип (т. е. обязательно проверить тип). b может быть чем угодно; и функция foo должна иметь возможность принимать любой тип в качестве второго параметра.

Рассмотрим функцию const из Prelude:

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

Откуда он «знает», что такое b (или a, если уж на то пошло)?

person newacct    schedule 14.07.2010