Haskell/GHC: докладвани са припокриващи се екземпляри, докато контекстът позволява само един

Уважаеми експерти на Haskell/GHC,

Наистина не разбирам защо GHC отчита припокриващи се случаи, докато само един всъщност е валиден според предоставените контексти. Например, нека разгледаме следната част от кода:

{-# LANGUAGE FlexibleInstances #-}

class C a where
    foo :: a -> String
    foo x = "OK"

instance C Bool
instance (C a) => C [a]
instance (C a) => C [(Char, a)]

main = print $ foo [('a', True)]

Компилирането му дава:

Test.hs:13:16: error:
    * Overlapping instances for C [(Char, Bool)]
        arising from a use of `foo'
      Matching instances:
        instance C a => C [a] -- Defined at Test.hs:9:10
        instance C a => C [(Char, a)] -- Defined at Test.hs:11:10
    * In the second argument of `($)', namely `foo [('a', True)]'
      In the expression: print $ foo [('a', True)]
      In an equation for `main': main = print $ foo [('a', True)]

Въпросът е, че ('a', True) има тип (Char, Bool), който не е екземпляр на C. Следователно instance C a => C [a] не е приложимо към стойността [('a', True)].

Следователно, защо GHC го разглежда?

Въпросът наистина е за разбирането на поведението на GHC, а не за това как да се избегне проблемът (напр. използване на OverlappingInstances). Дали защото контекстите не се използват при "разрешаване" на извикване на функция? И ако да защо?

Благодаря предварително!


person Didier Pieroux    schedule 06.01.2017    source източник


Отговори (1)


Моето разбиране (може да е много погрешно):

Първо, от документация:

При съпоставяне GHC не взема предвид контекста на декларацията на екземпляра (context1 и т.н.). Поведението по подразбиране на GHC е, че точно един екземпляр трябва да съответства на ограничението, което се опитва да разреши. Добре е да има потенциал за припокриване (чрез включване на двете декларации (A) и (B), да речем); грешка се съобщава само ако определено ограничение съвпада с повече от едно.

Флагът -XOverlappingInstances инструктира GHC да позволи съвпадение на повече от един екземпляр, при условие че има най-специфичен.

Във вашия случай типът, предаден на foo, е [(Char,Bool)]. Това удовлетворява общото [a] и по-специализираното [(Char,a)]. При липса на флаг OverlappingInstances, най-специфичният сценарий за съвпадение не се прилага и се съобщава за грешка.

Сега, ако промените леко кода си така:

instance C Bool
instance (C a) => C [a]
instance (C a) => C (Char, a)

Тогава няма да има припокриване, защото кортежът не е списък.

person shree.pat18    schedule 06.01.2017
comment
Благодаря много Shree. Така че в общи линии изглежда, че това е просто начинът, по който GHC работи с това (нестандартно) разширение. Заключвам въпроса. - person Didier Pieroux; 07.01.2017