Попытка понять Haskell =› против определения типов

Зачем в Haskell определять функцию с ограничением типа:

ghci> :t (==)  
(==) :: (Eq a) => a -> a -> Bool

Вместо того, чтобы определять его, чтобы его тип был:

ghci> :t (==)  
(==) :: Eq -> Eq -> Bool

person sneeu    schedule 28.06.2010    source источник
comment
эти два утверждения не равны   -  person Valentin Golev    schedule 29.06.2010


Ответы (2)


Вы бы не стали делать вторую версию, потому что получили бы ошибку компиляции. Eq - это не тип, это класс типов. Вы не можете использовать класс типов в местах, где требуется тип.

Если вы определили свой собственный тип MyEq, а затем определили функцию == с типом MyEq -> MyEq -> Bool, выражение "hello" == "hello" было бы недопустимым, поскольку "hello" является значением типа String, а не типа MyEq. Поскольку в haskell нет подтипов, значение не может быть одновременно типа String и типа MyEq.

Итак, если вы хотите определить функцию, которая может принимать значения разных типов, отвечающих определенным условиям, вам нужны классы типов.

person sepp2k    schedule 28.06.2010
comment
Чтобы продолжить, посмотрите на ошибку, которую вы получаете при запуске let a :: Eq -> Eq -> Bool ; a b c = b == c ; in a 2 2 в ghci. - person Aidan Cully; 29.06.2010
comment
Спасибо, ребята, это исправляет ситуацию! - person sneeu; 29.06.2010

В Haskell «тип» может иметь только один конкретный набор возможных значений, который не пересекается ни с каким другим типом. Не бывает такого, чтобы один тип был «другим видом» или «подтипом» другого типа.

Когда нам нужен полиморфизм, т. е. функции, которые могут применяться более чем к одному типу, мы можем указать это, используя переменную типа в сигнатуре типа функции.

Но переменная типа вообще может ссылаться на любой тип. Мы не всегда знаем, как определить нашу функцию для абсолютно каждого типа. Например, функция (>) имеет смысл только для типов, элементы которых сопоставимы. Компилятор отклонит функцию, чья сигнатура типа слишком общая, чтобы помочь нам избежать тарабарщины.

В вашем примере Eq не является типом. Это класс типов — имя для набора типов. Мы объявляем имена классов типов, используя ключевое слово class, и добавляем типы в класс, используя ключевое слово instance. Назначение класса типов состоит в том, чтобы использовать его в ограничении для ограничения области действия переменной типа.

Подход Haskell к типам и полиморфизму основан на «системе типов Хиндли-Милнера». Это чрезвычайно точный, но очень выразительный способ описания данных, который упрощает предоставление компилятору огромного количества сведений о типах в вашей программе. Этот интеллект помогает компилятору автоматически определять типы, оказывать вам большую помощь в корректировке вашей программы и оптимизировать скомпилированный результат, помимо других преимуществ.

Но будьте осторожны — это сильно отличается от того, как типы используются в ООП, к чему вы, возможно, привыкли. Обычно нет прямого перевода между объектно-ориентированной программой и программой на Haskell. Вы должны думать о задаче по-другому с самого начала. Будьте особенно осторожны, чтобы не спутать понятия Haskell "класс" и "экземпляр" с совершенно другим способом использования этих слов в ООП.

person Yitz    schedule 28.06.2010
comment
это сильно отличается от того, как типы используются в ООП, я не согласен. Классы типов Haskell действительно похожи на абстрактные классы или интерфейсы в ООП, и я подозреваю, что некоторая виртуальная таблица передается вместе с аргументами в полиморфную функцию для выполнения диспетчеризации во время выполнения. - person Alexandre C.; 30.06.2010