Как различные прагмы "..Instances" работают вместе, и есть ли способ обойти мою текущую проблему? - PullRequest
0 голосов
/ 18 апреля 2020

Рассмотрим следующий код:

{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE UndecidableInstances #-}
class X a
class Y a
instance Y Bool
instance (Y a) => X a
instance {-# OVERLAPPING #-} X Int

f :: (X a) => a -> a
f x = x

Эти прагмы ЯЗЫКА необходимы для написания приведенных выше примеров.

Теперь, скажем, мы хотим написать функцию g:

g :: (Y a) => a -> a
g = f

Без IncoherentInstances или добавления {- # INCOHERENT # -} в один из экземпляров, это не проверка типов. Но когда мы добавим это и спросим ghci

ghci> :t f
f :: Y a => a -> a

Внезапно тип 'f' изменился?

В этом небольшом примере программы все еще проверяют тип, когда я задаю f Int (указывая что вышеупомянутое было бы просто «визуальной ошибкой», но в более крупном примере то же самое не проверяет тип, давая мне ошибку вроде:

Could not deduce (Y a) arising from a use of 'f
(...)
from the context: (..., X a, ...)

Это также происходит, когда мы говорим

h = f

и попробуйте позвонить h с Int

1 Ответ

2 голосов
/ 18 апреля 2020

:type f не сообщает тип определенного объекта f. Сообщает тип выражения f. GH C изо всех сил старается избавиться от полиморфизма выражений. В частности, использование f в выражении вызывает упрощение ограничения X a (как и любое определение с ограничением). Без IncoherentInstances GH C воздерживается от использования instance Y a => X a, потому что есть другой экземпляр, который перекрывает его, поэтому GH C должен ждать, чтобы увидеть, какой из них следует использовать. Это обеспечивает согласованность; экземпляр only X Int, который когда-либо использовался, является явно "специализированным". С IncoherentInstances вы говорите, что вас не волнует согласованность, поэтому GH C идет дальше и упрощает X a до Y a, используя экземпляр polymorphi c всякий раз, когда f появляется в выражении. Странное поведение, которое вы видите, когда иногда GH C в порядке с X Int и иногда жалуется, что Y Int не является результатом того, что GH C принимает различные внутренние решения о том, когда он хочет упростить ограничения (вы сделали попросить бессвязность !). Команда для просмотра типа определения - :type +v. :type +v f должен показывать тип f "как объявлено". Надеюсь, вы также видите, что IncoherentInstances - плохая идея. Не используйте его.

...