multirec-0.6: src/Generics/MultiRec/Eq.hs
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
-----------------------------------------------------------------------------
-- |
-- Module : Generics.MultiRec.Eq
-- Copyright : (c) 2008--2010 Universiteit Utrecht
-- License : BSD3
--
-- Maintainer : generics@haskell.org
-- Stability : experimental
-- Portability : non-portable
--
-- Generic equality.
--
-----------------------------------------------------------------------------
module Generics.MultiRec.Eq where
import Generics.MultiRec.Base
-- * Generic equality
class HEq phi f where
heq :: (forall ix. phi ix -> r ix -> r ix -> Bool) ->
phi ix -> f r ix -> f r ix -> Bool
class Eq1 f where
eq1 :: (a -> a -> Bool) -> f a -> f a -> Bool
-- TODO: Think about more generic instances
instance Eq1 [] where
eq1 eq [] [] = True
eq1 eq (x1:xs1) (x2:xs2) = eq x1 x2 && eq1 eq xs1 xs2
eq1 eq _ _ = False
instance Eq1 Maybe where
eq1 eq Nothing Nothing = True
eq1 eq (Just x1) (Just x2) = eq x1 x2
eq1 eq _ _ = False
instance El phi xi => HEq phi (I xi) where
heq eq _ (I x1) (I x2) = eq proof x1 x2
-- | For constant types, we make use of the standard
-- equality function.
instance Eq a => HEq phi (K a) where
heq eq _ (K x1) (K x2) = x1 == x2
instance HEq phi U where
heq eq _ U U = True
instance (HEq phi f, HEq phi g) => HEq phi (f :+: g) where
heq eq p (L x1) (L x2) = heq eq p x1 x2
heq eq p (R y1) (R y2) = heq eq p y1 y2
heq eq _ _ _ = False
instance (HEq phi f, HEq phi g) => HEq phi (f :*: g) where
heq eq p (x1 :*: y1) (x2 :*: y2) = heq eq p x1 x2 && heq eq p y1 y2
instance (Eq1 f, HEq phi g) => HEq phi (f :.: g) where
heq eq p (D x1) (D x2) = eq1 (heq eq p) x1 x2
-- The following instance does not compile with ghc-6.8.2
instance HEq phi f => HEq phi (f :>: ix) where
heq eq p (Tag x1) (Tag x2) = heq eq p x1 x2
instance (Constructor c, HEq phi f) => HEq phi (C c f) where
heq eq p (C x1) (C x2) = heq eq p x1 x2
eq :: (Fam phi, HEq phi (PF phi)) => phi ix -> ix -> ix -> Bool
eq p x1 x2 = heq (\ p (I0 x1) (I0 x2) -> eq p x1 x2) p (from p x1) (from p x2)
-- Note:
--
-- We do not declare an equality instance such as
--
-- instance (El phi ix, HEq phi (PF phi)) => Eq ix where
-- (==) = eq proof
--
-- because "phi" is not mentioned on the right hand side.
-- One datatype may belong to multiple families, and
-- although the generic equality instances should be
-- the same, there is no good way to decide which instance
-- to use.
--
-- For a concrete "phi", it is still possible to manually
-- define an "Eq" instance as above.