Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Overlapping instances in Haskell when I'd expect it not to overlap due to constraints

Reading the book Real world Haskell geting below example of Overlapping instances

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")]

By my understanding this won't be a overlapping, as [a] shouldn't be a choice, since The restriction on JSON [a] was that 'a' must be an instance itself of JSON. There is no instance of JSON for (String, a).

like image 623
Jammy Lee Avatar asked May 27 '13 15:05

Jammy Lee


2 Answers

By my understanding this won't be a overlapping, as [a] shouldn't be a choice, since The restriction on JSON [a] was that a must be an instance itself of JSON. There is no instance of JSON for (String, a).

That's a misunderstanding. GHC does the instance selection taking only the instance head into account, and not any constraints on the instances.

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

means for the purpose of instance selection the same as

instance JSON [a] where

also the context of

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

is ignored for instance selection.

Thus GHC sees the two instances

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

and they both match the required

instance JSON [(String, String)]

that means you have overlap (regardless of what instances actually exist and what constraints each of the two instances has).

If an instance is selected, then the constraints are taken into account, and if they are not met, that is a type error.

like image 57
Daniel Fischer Avatar answered Oct 24 '22 17:10

Daniel Fischer


These exist

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

So there'd be an overlap even if GHC took context into account (see Daniel Fischer's answer).

like image 44
J. Abrahamson Avatar answered Oct 24 '22 17:10

J. Abrahamson