Skip to content

Instantly share code, notes, and snippets.

@Icelandjack
Created May 27, 2017 16:48
Show Gist options
  • Select an option

  • Save Icelandjack/e42495341f6029aad8c7e4e4a12c34ce to your computer and use it in GitHub Desktop.

Select an option

Save Icelandjack/e42495341f6029aad8c7e4e4a12c34ce to your computer and use it in GitHub Desktop.
Define multiple instances simultaneously
@Icelandjack
Copy link
Copy Markdown
Author

Icelandjack commented May 27, 2017

Not so nice for type constructors

newtype B a = MkB a

type EOSA = Eq & Ord & Show & Arbitrary

instance EOSA b => EOSA (B b) where
  (==) :: B b -> B b -> Bool
  MkB a == MkB b = a `compare` b
  
  compare :: B b -> B b -> Ordering
  MkB a `compare` MkB b = a `compare` b
  
  show :: B b -> String
  show (MkB b) = "MkB " ++ show b
  
  arbitrary :: Gen (B b)
  arbitrary = MkB <$> arbitrary

Now all of a sudden (==) @(B _) :: EOSA b => B b -> B b -> Bool which is ridiculous. We should be able to tailor the context to each method or group of methods.

@Icelandjack
Copy link
Copy Markdown
Author

It could be magic... (inferred from methods, and then crushed together) or determined from explicit instance sigs (and then crushed)

instance EOSA (B b) where
  (==) :: Eq b => B b -> B b -> Bool
  MkB a == MkB b = a == b

  compare :: B b -> B b -> Ordering
  MkB a `compare` MkB b = a `compare` b

  show :: Show b => B b -> String
  show (MkB b) = "MkB " ++ show b 
...

and the methods have the same constraints as provided, and the instances become

instance Eq        b => Eq        (B b)
instance Ord       b => Ord       (B b)
instance Show      b => Show      (B b)
instance Arbitrary b => Arbitrary (B b)

@Icelandjack
Copy link
Copy Markdown
Author

So if inferred from method's required constraints, then we have

instance EOSA (B b) where
  a == b = compare a b == EQ
  MkB a `compare` MkB b = compare a b

resulting in

instance Ord a => Eq  (B b)
instance Ord a => Ord (B b)

@Icelandjack
Copy link
Copy Markdown
Author

We merge the contexts of methods from the same type class just as usual

class  EQ a where  eq :: a -> a -> Bool
class NEQ a where neq :: a -> a -> Bool

newtype C a = C a
  deriving (EQ, NEQ)

instance (EQ a, NEQ a) => Eq (C a) where
  (==) = eq
  (/=) = neq

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment