Damian Nadales
Damian Nadales

Reputation: 5037

Why do I get a "constraint matches instance declaration" error?

I have the following instances:

instance (Typeable crypto, ToCBOR (SIPHash crypto)) => ToCBOR (SIP crypto) where
  -- ...

instance (Typeable crypto, ToCBOR (Hash crypto SIPData)) =>ToCBOR (SIPHash crypto) where
  -- ...

Which give rise to the following error:

• The constraint ‘ToCBOR (SIPHash crypto)’
    matches an instance declaration
  instance (Typeable crypto, ToCBOR (Hash crypto SIPData)) =>
           ToCBOR (SIPHash crypto)
    -- Defined at src/Cardano/Ledger/Spec/STS/Update/Data.hs:383:10
  This makes type inference for inner bindings fragile; 
    either use MonoLocalBinds, or simplify it using the instance 
• In the context: (Typeable crypto, ToCBOR (SIPHash crypto))
  While checking an instance declaration
  In the instance declaration for ‘ToCBOR (SIP crypto)’

Why do I get this error, and what is this "match" the compiler error is referring to? (as far as I can see the constraints are different).

PS: I also tried removing the Typeable crypto constraint without any luck, I guess this is due to the compiler not looking at the LHS of the instance declaration.

Upvotes: 4

Views: 461

Answers (1)

Essentially, Haskell is telling you that, as written, these instances will make certain kinds of type inference that you might normally expect to work impossible. The MonoLocalBinds language extension changes the way that the type system deals with these scenarios, so enabling it will allow your instances to function as written, but may change the semantics of your code.

Haskell normally uses the most general (most polymorphic) interpretation of a variable bound by let or where, but if you allow these sorts of instances, there may be multiple different, yet equally general, interpretations. MonoLocalBinds will cause the parser to use a less general interpretation, instead of grinding to a halt or making an arbitrary decision. There's an 80-page paper from Vytiniotis, et al that explains this issue more fully, though admittedly, I don't have time to sit down and read it.

As @chi points out, GHC is letting you know that you can avoid this problem altogether (in this case) by replacing your first instance with:

instance (Typeable crypto, ToCBOR (Hash crypto SIPData)) => ToCBOR (SIP crypto)

Upvotes: 3

Related Questions