Trying to generalise (+) to more than just Nums, I wrote a up an Addable class:
{-# LANGUAGE FlexibleContexts, FlexibleInstances, UndecidableInstances #-}
class Addable a where
(+) :: Addable a => a -> a -> a
instance Addable [a] where
(+) = (++)
instance Num a => Addable a where
(+) = (Prelude.+)
When trying to add (concatenate) lists, GHC complains about overlapping instances:
*Test> "abc" + "defghi"
<interactive>:84:7:
Overlapping instances for Addable [Char] arising from a use of `+'
Matching instances:
instance Num a => Addable a -- Defined at Utils.hs:23:10
instance Addable [a] -- Defined at Utils.hs:20:10
In the expression: "abc" + "defghi"
In an equation for `it': it = "abc" + "defghi"
I know that GHC disregards context when choosing instances of typeclasses, so trying to choose between Addable [a] and Addable a is indeed a problem. However, I expect GHC to choose the first definition since it is more specific. Why isn't that happening?
Furthermore, is there an elegant workaround for this problem? Or am I going at this from the wrong angle?
You need to enable overlapping instances in order to actually use them. In older versions of the compiler, you could do this per-module with the OverlappingInstances extension:
{-# LANGUAGE OverlappingInstances #-}
This works properly for this code:
λ> :set -XOverlappingInstances
λ> "abc" + "def"
"abcdef"
However, this approach is deprecated in newer versions of GHC (at least in 8.0):
Misc.hs:1:73-92: warning: …
-XOverlappingInstances is deprecated:
instead use per-instance pragmas OVERLAPPING/OVERLAPPABLE/OVERLAPS
So the more modern approach is to specify this on a per-instance basis:
instance {-# OVERLAPPABLE #-} Num a => Addable a where
(+) = (Prelude.+)
This style of pragma also exists for OVERLAPPING, OVERLAPS and INCOHERENT, letting you annotate specific instances with these properties.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With