Соответствие экземпляров для переменных * generic c работает таким образом, чтобы предотвратить некоторые потенциально запутанные (и опасные) сценарии ios.
Если компилятор поддался вашей интуиции и выбрал EqM a b
Например, при компиляции aretheyeq
(поскольку a
и b
не обязательно объединяют, как вы говорите), следующий вызов:
x = aretheyeq (Left 'z') (Right 'z')
вернет False
, что противоречит интуиции .
Q : подождите секунду! Но в этом случае a ~ Char
и b ~ Char
, и у нас также есть Eq a
и Eq b
, что означает Eq Char
, что должно позволить выбрать экземпляр EqM a a
, не так ли?
Ну, да, я полагаю, что может происходить в теории, но Haskell просто так не работает. Экземпляры класса - это просто дополнительные параметры, передаваемые в функции (как словари методов), поэтому для того, чтобы существовал экземпляр, он должен быть однозначно выбран внутри самой функции, или , который должен быть передан из Потребитель.
Первый (однозначно выбираемый экземпляр) обязательно требует наличия только одного экземпляра. И действительно, если вы удаляете экземпляр EqM a a
, ваша функция компилируется и всегда возвращает False
.
Последнее (передача экземпляра от потребителя) означает ограничение на функцию, например:
aretheyeq :: EqM a b => Either a b -> Either a b -> Bool
Что вы спрашиваете, так это то, что Haskell по существу имеет две разные версии этой функции: одна требует a ~ b
и выбирает экземпляр EqM a a
, а другая не требует этого и выбирает EqM a b
экземпляр.
И тогда компилятор ловко выберет «правильную» версию. Так что если я вызываю aretheyeq (Left 'z') (Right 'z')
, вызывается первая версия, а если я звоню aretheyeq (Left 'z') (Right 42)
- вторая.
Но теперь подумайте дальше: есть ли две версии aretheyeq
и какая выбор зависит от того, равны ли типы, а затем подумайте:
dummy :: a -> b -> Bool
dummy a b = aretheyeq (Left a) (Right b)
Как dummy
узнает, какую версию aretheyeq
выбрать? Так что теперь должно быть две версии dummy
: одна для случая a ~ b
и другая для других случаев.
И так далее. Эффект пульсации продолжается, пока не появятся конкретные типы.
Q : подождите секунду! Почему две версии? Разве не может быть только одной версии, которая затем решает, что делать, основываясь на том, в какие аргументы передаются?
Ах, но это невозможно! Это потому, что типы стираются во время компиляции. К тому времени, когда функция начинает работать, она уже скомпилирована, и информации о типе больше нет. Таким образом, все должно быть решено во время компиляции: какой экземпляр выбрать, и волновой эффект от него.