Ответ 1
Это действительно довольно просто. Позвольте спросить GHCi, что тип isList2
:
∀x. x ⊢ :t isList2
isList2 :: a -> Bool
Это не соответствует экземпляру [a]
(даже если он может, через унификацию), но он сразу соответствует экземпляру a
. Поэтому GHC выбирает экземпляр a
, поэтому isList2
возвращает False
.
Это то, что означает IncoherentInstances
. На самом деле, это довольно хорошая демонстрация.
Весело, если вы просто отключите IncoherentInstances
, мы получим точно противоположный эффект, и GHCi теперь говорит следующее:
∀x. x ⊢ :t isList2
isList2 :: [Integer] -> Bool
Это происходит потому, что isList2
- это привязка верхнего уровня, не определенная с использованием синтаксиса функций, и, таким образом, подчиняется Ограниченному ограничению мономорфизма. Таким образом, он становится специализированным для экземпляра, с которым он фактически использовался.
Добавив NoMonomorphismRestriction
, а также отключив IncoherentInstances
, мы получим это вместо:
∀x. x ⊢ :t isList2
isList2 :: IsList a => a -> Bool
∀x. x ⊢ isList2 'a'
False
∀x. x ⊢ isList2 "a"
True
∀x. x ⊢ isList2 undefined
<interactive>:19:1:
Overlapping instances for IsList a0 arising from a use of `isList2'
Какое ожидаемое совпадающее поведение с выбранным экземпляром основано на использовании и жалобах, если выбор неоднозначен.
Что касается редактирования вопроса, я не считаю, что желаемый результат возможен без аннотаций типа.
Первый вариант - предоставить isList2
подпись типа, которая не позволяет IncoherentInstances
выбирать экземпляр слишком рано.
isList2 :: (IsList a) => a -> Bool
isList2 = isList
Вам, вероятно, придется делать то же самое в другом месте isList
упоминается (даже косвенно) без применения к аргументу.
Второй вариант состоит в том, чтобы устранить неоднозначность числовых литералов и отключить IncoherentInstances
.
main =
print (isList (42 :: Integer)) >>
print (isList2 (42 :: Integer)) >>
print (isList [42]) >>
print (isList2 [42])
В этом случае достаточно информации, чтобы выбрать наиболее конкретный экземпляр, поэтому OverlappingInstances
выполняет свою работу.