{-# LANGUAGE FlexibleContexts #-}
{-
[Summary of the program] Ring is defined as a subclass of Semigroup,
inheriting multiplication. Additive is a wrapper that extracts the additive
structure of Ring and reifies it as Semigroup. For simplicity, the code omits
ring operations (+ and *) and defines only the additive and multiplicative
identities.
[The bug] If there is a cyclic class hierarchy like
class B a => Semigroup a where ...
class Semigroup (Additive a) => Ring a where ...
instance Ring a => Semigroup (Additive a) where ...
then uses of B's methods on (Additive a) in the method implementations of the
third declaration "instance Ring a => Semigroup (Additive a)" will:
1. be accepted by the compiler even in cases where B (Additive a) is not
derivable.
2. result in <>.
-}
class B a where
b :: a
class B a => Semigroup a where
unit :: a
class (Semigroup a, Semigroup (Additive a)) => Ring a where
zero :: a
newtype Additive a = Additive a
-- The source compiles whether with or without this instance declaration in GHC
-- 7.2.1 - 7.4.1 and produces <>.
--
-- GHC 7.0.4 rejects this source without this declaration and produces
-- terminating code with the declaration.
instance B a => B (Additive a) where
b = Additive b
instance Ring a => Semigroup (Additive a) where
unit = b -- Use a method of type (B a => ...) with a instantiated as
-- (Additive a). This causes <>.
-- Now try to instantiate Ring and evaluate `unit'.
instance B Int where
b = 1234567890
instance Semigroup Int where
unit = 1
instance Ring Int where
zero = 0
main = case (unit :: Additive Int) of -- Force the additive identity of Int.
Additive x -> print x