I'm experimenting with defining UpperBounded and LowerBounded typeclasses. An example type belonging to the latter that is not also Bounded would be type Natural from Numeric.Natural.
I want to say that if a type is Bounded, then it is also UpperBounded and LowerBounded. If a type is both UpperBounded and LowerBounded, then it is also Bounded.
To express the constraints, I need FlexibleInstances and UndecidableInstances extensions. These allow the module to load into ghci (8.4.2) with only a warning, but, without the INCOHERENT pragmas, I get an overlapping instance error if I try to evaluate minBound, maxBound, upperBound or lowerBound instantiated to either of the types Foo or Bar.
A solution is to apply the INCOHERENT pragma to the instances at lines 11, 14 and 17. Reading over section 10.8.3.6. Overlapping instances in the GHC User Guide, I believe I understand. (Is there a better solution?)
In the paste, I have INCOHERENT pragmas only at lines 11 and 17. This gives me the following behaviour in ghci:
- minBound, maxBound, upperBound and lowerBound instantiated to type Foo all function as expected, evaluating to the appropriate lower or upper bound.
- upperBound and maxBound instantiated at Bar give overlapping instance errors for UpperBounded, as expected.
- lowerBound :: Bar evaluates to C, as expected.
- minBound :: Bar gives an overlapping instance error for UpperBounded:
*UpperLowerBounded> minBound :: Bar
<interactive>:141:1: error:
• Overlapping instances for UpperBounded Bar
arising from a use of ‘minBound’
Matching instances:
instance [safe] Bounded a => UpperBounded a
-- Defined at UpperLowerBounded.hs:14:10
instance [safe] UpperBounded Bar -- Defined at UpperLowerBounded.hs:31:10
• In the expression: minBound :: Bar
In an equation for ‘it’: it = minBound :: Bar
It's #4 that I don't understand. An explanation would be very much appreciated. (Also, what's a [safe] instance?)
Regards,
Graham