2013-05-27 2 views
8

Читая книгу Real world Haskell Geting ниже пример перекрывающихся экземпляровПерекрытие экземпляры в Haskell

instance (JSON a) => JSON [a] where 
    toJValue = undefined 
    fromJValue = undefined 

instance (JSON a) => JSON [(String, a)] where 
    toJValue = undefined 
    fromJValue = undefined 

ghci> toJValue [("foo","bar")] 

<interactive>:1:0: 
    Overlapping instances for JSON [([Char], [Char])] 
     arising from a use of `toJValue' at <interactive>:1:0-23 
Matching instances: 
    instance (JSON a) => JSON [a] 
    -- Defined at BrokenClass.hs:(44,0)-(46,25) 
    instance (JSON a) => JSON [(String, a)] 
    -- Defined at BrokenClass.hs:(50,0)-(52,25) 
    In the expression: toJValue [("foo", "bar")] 
    In the definition of `it': it = toJValue [("foo", "bar")] 

По моему пониманию это не будет перекрытием, так как [а] не должен быть выбор, так как ограничение JSON [a] заключался в том, что «a» должен быть экземпляром JSON. Для JSON нет экземпляра (String, a).

ответ

17

По моему пониманию это не будет перекрытием, а [a] не должен быть выбор, так как ограничение на JSON [a], что a должен быть экземпляром сама JSON. Нет примера JSON для (String, a).

Это недоразумение. GHC делает выбор экземпляра, учитывающего только заголовок экземпляра, а не ограничения на экземпляры.

instance (JSON a) => JSON [a] where 

средства с целью выбора экземпляра такой же, как

instance JSON [a] where 

также контекст

instance (JSON a) => JSON [(String, a)] where 

игнорируется для выбора экземпляра.

Таким образом GHC видит два экземпляра

instance JSON [a] 
instance JSON [(String, a)] 

и оба они соответствуют требуемой

instance JSON [(String, String)] 

, что означает, что у вас есть перекрытие (независимо от того, что случаи действительно существуют, и какие ограничения каждого из этих двух случаев есть).

Если выбран экземпляр, то ограничения учитываются, и если они не выполняются, это ошибка типа.

+0

благодарит за очень подробное объяснение –

+0

К слову: чуть позже в книге указывается, что вы можете использовать прагму «OverlappingInstances» для «решения» проблемы, описанной в этом ответе. Лично я не понимаю, почему так оно и есть. Надеюсь, когда-нибудь я его выпью. – Brendan

5

Они существуют

ghci> :i ToJSON 
... 
instance ToJSON [Char] 
... 
instance (ToJSON a, ToJSON b) => ToJSON (a, b) 

Так что бы перекрытие, даже если GHC принял во внимание контекст (см ответ Дэниела Фишера).

Смежные вопросы