Это что-то вроде философского вопроса, но я надеюсь, что на него ответила официальная документация или «слово божье» (читай: SPJ). Есть ли конкретная причина, по которой комитет Haskell решил потребовать явные интерфейсы в форме классов типов, а не более единообразное решение, основанное на сопоставлении с образцом?
В качестве примера возьмем Eq:
class Eq a where
(==), (/=) :: a -> a -> Bool
x == y = not $ x /= y
x /= y = not $ x == y
instance Eq Int where
(==) = internalIntEq
Почему бы нам не сделать что-то подобное вместо этого (потерпите псевдо-Haskell):
(==), (/=) :: a -> a -> Bool
default x == y = not $ x /= y -- 1
default x /= y = not $ x == y
(Int a) == (Int b) = a `internalIntEq` b -- 2
То есть, если бы Haskell разрешал сопоставление с образцом обычных типов данных, то:
Программисты могут создавать специальные классы, т. е.
instanceбудет неявным (2)Типы по-прежнему можно было вывести и сопоставить статически (
SupportsEqualsEquals a => ...)Реализации по умолчанию будут поставляться «бесплатно»
Классы могут быть легко расширены, ничего не нарушая
Должен быть способ указать шаблон по умолчанию (1), который, хотя и объявлен раньше других, всегда соответствует последнему. Противоречат ли какие-либо из этих гипотетических функций чему-то, что присуще Haskell? Стало бы сложно или невозможно правильно определять типы? Похоже, это мощная функция, которая очень хорошо сочетается с остальной частью Haskell, поэтому я полагаю, что есть веская причина, по которой мы не делаем это таким образом™. Является ли этот механизм специального полиморфизма просто слишком специальным?
id :: a -> aилиfst :: (a,b) -> a, просто по их сигнатурам, потому что у них есть только параметрический полиморфизм. Если у вас есть какой-то механизм typecase, вы теряете параметричность. Например,a -> a -> Boolдопускает только две (всего) реализации в Haskell (const $ const Trueиconst $ const False); если у вас typecase, то вы теряете эту гарантию. - person Antal Spector-Zabusky   schedule 02.02.2012id :: a -> a, а затем определитьid (Int i) = i + 1? Потому что это не так: последнее определение будет иметь типSupportsPlus a => a -> a, что несовместимо. - person Jon Purdy   schedule 02.02.2012(==)задается какa -> a -> Bool. Если вам нужно указать класс типовSupportsEquals, то, похоже, все, что вы сделали, это изменили синтаксис --- я не понимаю, почему он другой. И я не думаю, что он может выражать классы типов с несколькими параметрами, функциональные зависимости или ассоциированные типы, хотя этого, конечно, не было в первоначальном плане. На самом деле, может ли он даже выражать классы типов более высокого порядка? Откуда вы знаете, чтоreturn :: a -> m aдолжно быть ad-hoc поверхm, а неa? - person Antal Spector-Zabusky   schedule 02.02.2012iявно являетсяInt, как это могло быть изменено наSupportsPlus a => a? Применяется ли одно и то же правило обобщения ко всем определениям или только к тем, которые используют нотацию typecase? Означает ли это, что даже при отсутствии глобальной подписиid :: a -> aid (Int i) = i + 1имеет типSupportsPlus a => a -> a"? If so, what are the semantics of expressions likeid 3.7`? - person Doug McClean   schedule 02.02.2012Monadможет быть там, где это не удается. Не могли бы вы помочь мне с конкретным примером? - person Jon Purdy   schedule 02.02.2012SupportsPlus(или как бы это ни называлось) происходит от использования+в (неправильном) определенииid. Однако я вижу, в чем я был не прав — междуInt -> IntиSupportsPlus a => a -> aесть некоторая двусмысленность, потому что ни одно из них не является полностью правильным. - person Jon Purdy   schedule 02.02.2012(==)ошибочен? Что касается случаев, которые кажутся проблематичными: переменные типа более высокого типа и типы в позициях без аргументов. РассмотримmaxBound :: Enum a => aилиfmap :: Functor f => (a -> b) -> (f a -> f b)--- как здесь будет работать сопоставление? (Кстати, мне нравится вопрос, даже если я не совсем разбираюсь в деталях.) - person Antal Spector-Zabusky   schedule 02.02.2012