packages feed

pointless-rewrite-0.0.3: src/Data/Equal.hs

-----------------------------------------------------------------------------
-- |
-- Module      :  Data.Equal
-- Copyright   :  (c) 2010 University of Minho
-- License     :  BSD3
--
-- Maintainer  :  hpacheco@di.uminho.pt
-- Stability   :  experimental
-- Portability :  non-portable
--
-- Pointless Rewrite:
-- automatic transformation system for point-free programs
-- 
-- Implementation of type and function equality at the value-level.
--
-----------------------------------------------------------------------------

module Data.Equal where

import Data.Type
import Data.Pf
import Data.Spine

import Control.Monad hiding (Functor(..))
import Unsafe.Coerce
import Control.Monad.State as ST hiding (Functor(..))
import Control.Monad.Reader hiding (Functor(..))
import Data.Map as Map
import Data.List as List
import Prelude hiding (Functor(..))

import Generics.Pointless.Functors hiding (rep)

data Equal a b where
    Eq :: Equal a a

teqBool :: Type a -> Type b -> Bool
teqBool a b = maybe False (const True) (teq a b)

type Vars = Map String DynType

-- type equality where the left-side type may have unbounded variables, representing pattern-matching
teqvar :: MonadPlus m => Type a -> Type b -> StateT Vars m (Equal a b)
teqvar (Var n) a = do
    vars <- ST.get
    case (Map.lookup n vars) of
    { Just (DynT t) -> do
        Eq <- teq t a
        return (unsafeCoerce Eq)
    ; otherwise -> do
        ST.put (Map.insert n (DynT a) vars)
        return (unsafeCoerce Eq)
    }
teqvar Any _ = return (unsafeCoerce Eq)
teqvar _ Any = return (unsafeCoerce Eq)
teqvar (Id a) (Id b) = teqvar a b
teqvar One One = return Eq
teqvar Int Int = return Eq
teqvar Bool Bool = return Eq
teqvar Char Char = return Eq
teqvar (Prod a b) (Prod c d) = do
	Eq <- teqvar a c
	Eq <- teqvar b d
	return Eq
teqvar (Either a b) (Either c d) = do
	Eq <- teqvar a c
	Eq  <- teqvar b d
	return Eq
teqvar (Data s fx) (Data s' fy) = do
    guard (sameName s s')
    Eq <- feqvar fx fy
    return (unsafeCoerce Eq)
teqvar (NewData s fx) (NewData s' fy) = do
    guard (sameName s s')
    Eq <- feqvar fx fy
    return (unsafeCoerce Eq)
teqvar (List a) (List b) = do
    Eq <- teqvar a b
    return Eq
teqvar (Fun a b) (Fun c d) = do
    Eq <- teqvar a c
    Eq <- teqvar b d
    return Eq
teqvar (Lns a b) (Lns c d) = do
    Eq <- teqvar a c
    Eq <- teqvar b d
    return Eq
teqvar (Pf a) (Pf b) = do
    Eq <- teqvar a b
    return Eq
teqvar Dynamic Dynamic = return Eq
teqvar TP TP = return Eq
teqvar (TU a) (TU b) = do
    Eq <- teqvar a b
    return Eq
teqvar _ _ = mzero

teqvars :: MonadPlus m => Type a -> Type b -> m (Equal a b,Vars)
teqvars a b = runStateT (teqvar a b) Map.empty

-- regular type equality
teq :: MonadPlus m => Type a -> Type b -> m (Equal a b)
teq a b = evalStateT (teqvar a b) Map.empty

feqvar :: MonadPlus m => Fctr f -> Fctr g -> StateT Vars m (Equal (Fix f) (Fix g))
feqvar I I = return Eq
feqvar (K a) (K b) = do
    Eq <- teqvar a b
    return Eq
feqvar L L = return Eq
feqvar (f :*!: g) (h :*!: i) = do
    Eq <- feqvar f h
    Eq <- feqvar g i
    return Eq
feqvar (f :+!: g) (h :+!: i) = do
    Eq <- feqvar f h
    Eq <- feqvar g i
    return Eq
feqvar (f :@!: g) (h :@!: i) = do
    Eq <- feqvar f h
    Eq <- feqvar g i
    return Eq
feqvar AnyF f = return (unsafeCoerce Eq)
feqvar f AnyF = return (unsafeCoerce Eq)
feqvar _ _ = mzero

feq :: MonadPlus m => Fctr f -> Fctr g -> m (Equal (Fix f) (Fix g))
feq f g = evalStateT (feqvar f g) Map.empty

-- | Tests if a functor is recursive or not, by applying it to two distinct types.
isRec :: Fctr f -> Bool
isRec fctr = case teq (rep fctr Int) (rep fctr One) of { Just Eq -> False ; otherwise -> True }

-- | Syntactic equality, with the exception of protected values.
geq :: Type a -> a -> a -> Bool
geq (Pf t) (PROTECT x) y = geq (Pf t) x y
geq (Pf t) x (PROTECT y) = geq (Pf t) x y
geq (Pf t) (PROTECT_LNS x) y = geq (Pf t) x y
geq (Pf t) x (PROTECT_LNS y) = geq (Pf t) x y
geq t x y = geq' t x t y

geq' :: Type a -> a -> Type b -> b -> Bool
geq' a x b y = aux a b x y
    where aux :: Type a -> Type b -> a -> b -> Bool
          aux t1 t2 x y = aux' t1 (toSpine t1 x) t2 (toSpine t2 y)
          aux' :: Type a -> Spine a -> Type b -> Spine b -> Bool
          aux' _ (_ `As` c1) _ (_ `As` c2) = name c1 == name c2
          aux' t (f1 `Ap` (t1 :| a1)) t' (f2 `Ap` (t2 :| a2)) = aux' (Fun t1 t) f1 (Fun t2 t') f2 && aux t1 t2 a1 a2
          aux' _ _ _ _ = False

-- | Clone of |geq| with a specific case for top.
geqt :: Type a -> a -> a -> Bool
geqt (Pf t) (PROTECT x) y = geqt (Pf t) x y
geqt (Pf t) x (PROTECT y) = geqt (Pf t) x y
geqt (Pf t) (PROTECT_LNS x) y = geqt (Pf t) x y
geqt (Pf t) x (PROTECT_LNS y) = geqt (Pf t) x y
geqt t x y = geqt' t x t y

geqt' :: Type a -> a -> Type b -> b -> Bool
geqt' a x b y = aux a b x y
    where aux :: Type a -> Type b -> a -> b -> Bool
          aux t1 t2 x y = aux' t1 (toSpine t1 x) t2 (toSpine t2 y)
          aux' :: Type a -> Spine a -> Type b -> Spine b -> Bool
          aux' _ _ (Pf _) (TOP `As` _) = True
          aux' (Pf _) (As TOP _) _ _ = True
          aux' _ (_ `As` c1) _ (_ `As` c2) = name c1 == name c2
          aux' t (f1 `Ap` (t1 :| a1)) t' (f2 `Ap` (t2 :| a2)) = aux' (Fun t1 t) f1 (Fun t2 t') f2 && aux t1 t2 a1 a2
          aux' _ _ _ _ = False

-- | Explicitly coerce a value of a given type to another given type.
coerce :: MonadPlus m => Type a -> Type b -> a -> m b
coerce a b x = do Eq <- teq a b
                  return x

collectDyn :: MonadPlus m => Type a -> a -> m DynType
collectDyn a v = case collectDyn' a v of { Just d -> return d; otherwise -> mzero }
collectDyn' :: Type a -> a -> Maybe DynType
collectDyn' = collect q plus
    where q :: MonadPlus m => GenericQ (m DynType)
          q (Pf _) (MKDYN a) = return $ DynT a
          q _ _ = mzero
          plus :: Maybe DynType -> Maybe DynType -> Maybe DynType
          plus (Just (DynT a)) (Just (DynT b)) = teq a b >> return (DynT a)
          plus m Nothing = m
          plus Nothing n = n

collectNewNames :: Type a -> [String]
collectNewNames = List.map fst . Map.toList . collectNewDatas

collectNewDatas :: Type a -> Map String DynFctr
collectNewDatas = maybe Map.empty id . collect q mcat TypeRep
    where q :: MonadPlus m => GenericQ (m (Map String DynFctr))
          q TypeRep (NewData s f) = return $ Map.singleton s (DynF f)
          q _ _ = return Map.empty
          mcat m n = do { x <- m; y <- n; return (x `Map.union` y) }

{-
showDatas :: Type a -> String
showDatas = maybe [] id . collect q mcat TypeRep
    where q :: MonadPlus m => GenericQ (m String)
          q TypeRep d@(isData -> True) = return (showData d ++ "\n")
          q _ _ = return []
          mcat m n = do { x <- m; y <- n; return (x ++ y) }
-}
collectVars :: Type a -> [String]
collectVars = maybe [] id . collect q mcat TypeRep
    where q :: MonadPlus m => GenericQ (m [String])
          q TypeRep (Var s) = return [s]
          q _ _ = return []
          mcat m n = do { x <- m; y <- n; return (x ++ y) }

collect :: MonadPlus m => GenericQ (m r) -> (m r -> m r -> m r) -> Type a -> a -> m r
collect (q :: GenericQ (m r)) plus a x = collectSpine a (toSpine a x)
    where collectSpine :: MonadPlus m => Type a -> Spine a -> m r
          collectSpine t s@(As _ _) = q t (fromSpine s)
          collectSpine t s@(Ap f (a :| v)) = q t (fromSpine s)
            `plus` (collectSpine (Fun a t) f)
            `plus` (collectSpine a (toSpine a v))

-- | Find a value of type b inside a value of type a
find :: Type b -> b -> Type a -> a -> Bool
find b y a x = findSpine a (toSpine a x)
    where findSpine :: Type a -> Spine a -> Bool
          findSpine t (As v con) = case teq t b of {
              Just Eq   -> geqt t v y;
              otherwise -> False
              }
          findSpine t s@(Ap f (a :| v)) = (case teq t b of {
              Just Eq   -> geqt b y (fromSpine s);
              otherwise -> False
              })
              || findSpine (Fun a t) f
              || findSpine a (toSpine a v)

removeIds :: Type a -> a -> a
removeIds t x = fromSpine $ removeIdSpine t $ toSpine t x

removeIdSpine :: Type a -> Spine a -> Spine a
removeIdSpine TypeRep s@(fromSpine -> (Id a)) = removeIdSpine TypeRep (toSpine TypeRep a)
removeIdSpine t (As v con) = As v con
removeIdSpine t s@(Ap f (a :| v)) = Ap (removeIdSpine (Fun a t) f) (a :| fromSpine (removeIdSpine a (toSpine a v)))

unDyn :: Type a -> Dynamic -> a
unDyn t (Dyn a x) = case teq t a of { Just Eq -> x; otherwise -> error "unDyn failed"}

cast :: Type a -> Type b -> b -> a
cast a Dynamic (Dyn b x) = cast a b x
cast a b@(Data s f) x | isBasic a = case teq (rep f b) a of { Just Eq -> out x; otherwise -> error "type cast failed"}
cast a b@(NewData s f) x | isBasic a = case teq (rep f b) a of { Just Eq -> out x; otherwise -> error "type cast failed"}
cast a b x = case teq a b of { Just Eq -> x; otherwise -> error "type cast failed"}

isInt :: Type a -> Maybe (Equal a Int)
isInt a = teq a Int
isList :: Type a -> Maybe (Equal a [b])
isList a = teq a (List Any)
isNat :: Type a -> Maybe (Equal a Nat)
isNat a = teq a nat

-- infers a new functor for newly created recursive types
reshape :: MonadPlus m => Type a -> m DynType
reshape (NewData s f) = do
	let mark = Id Any
	DynF g <- reshapeF f
	FRep h <- inferFctr mark (rep g mark)
	return $ DynT $ NewData s h
reshape (Prod a b) = do
	DynT c <- reshape a	
	DynT d <- reshape b
	return $ DynT $ Prod c d
reshape (Either a b) = do
	DynT c <- reshape a	
	DynT d <- reshape b
	return $ DynT $ Either c d
reshape (List a) = do
	DynT b <- reshape a
	return $ DynT $ List b
reshape a = return $ DynT a
	
reshapeF :: MonadPlus m => Fctr f -> m DynFctr
reshapeF I = return $ DynF I
reshapeF (K a) = do
	DynT b <- reshape a
	return $ DynF $ K b
reshapeF L = return $ DynF L
reshapeF (f :*!: g) = do
	DynF h <- reshapeF f
	DynF i <- reshapeF g
	return $ DynF $ h :*!: i
reshapeF (f :+!: g) = do
	DynF h <- reshapeF f
	DynF i <- reshapeF g
	return $ DynF $ h :+!: i
reshapeF (f :@!: g) = do
	DynF h <- reshapeF f
	DynF i <- reshapeF g
	return $ DynF $ h :@!: i

data FctrRep a b where
    FRep :: (Functor f,Rep f a ~ b) => Fctr f -> FctrRep a b

-- Infers a new functor from a base type and an identity marker
inferFctr :: MonadPlus m => Type a -> Type b -> m (FctrRep a b)
inferFctr a (Prod x y) = do
    FRep f <- inferFctr a x
    FRep g <- inferFctr a y
    return $ FRep $ f :*!: g
inferFctr a (Either x y) = do
    FRep f <- inferFctr a x
    FRep g <- inferFctr a y
    return $ FRep $ f :+!: g
inferFctr a (List x) = do
    FRep f <- inferFctr a x
    return $ FRep $ L :@!: f
inferFctr a x = (do
    Eq <- teq a x
    return $ FRep I)
        `mplus` (do
    return $ FRep (K x))

-- Infers a new constant functor from a base type
-- The functor is always constant, i.e., forall a,b. Rep f a ~ Rep f b, altough this escapes the type-checker.
inferKFctr :: MonadPlus m => Type b -> m (FctrRep Dynamic b)
inferKFctr (Prod x y) = do
    FRep f <- inferKFctr x
    FRep g <- inferKFctr y
    return $ FRep $ f :*!: g
inferKFctr (Either x y) = do
    FRep f <- inferKFctr x
    FRep g <- inferKFctr y
    return $ FRep $ f :+!: g
inferKFctr (List x) = do
    FRep f <- inferKFctr x
    return $ FRep $ L :@!: f
inferKFctr x = return $ FRep (K x)

type TypeRule s = MonadPlus m => forall a. Type a -> StateT s m (Type a)
type FctrRule s = MonadPlus m => forall f. Fctr f -> StateT s m (Fctr f)

-- replaces the variables in an argument type with the concrete instantiations in the context.
replacevar :: MonadPlus m => Type a -> Vars -> m (Type a)
replacevar t vars = evalStateT (replace var none t) vars
	where
	var :: TypeRule Vars
	var (Var s) = do
		ctx <- ST.get
		case (Map.lookup s ctx) of
    			{ Just (DynT a) -> return (unsafeCoerce a)
    			; otherwise -> mzero }
        var _ = mzero
        none :: FctrRule Vars
        none f = mzero

replacedyn :: Type a -> Type a
replacedyn t = maybe t id $ evalStateT (replace dyn kdyn t) ()
	where dyn :: TypeRule ()
	      dyn Dynamic = return Any
	      dyn _ = mzero
	      kdyn :: FctrRule ()
	      kdyn (K Dynamic) = return AnyF
	      kdyn _ = mzero

replace,replace' :: TypeRule s -> FctrRule s -> TypeRule s
replace tr fr t = tr t `mplus` replace' tr fr t
replace' tr fr (Var s) = return $ Var s
replace' tr fr (Id a) = do
	x <- replace tr fr a
	return (Id x)
replace' tr fr Int = return Int
replace' tr fr Bool = return Bool
replace' tr fr Char = return Char
replace' tr fr One = return One
replace' tr fr (Either a b) = do
	x <- replace tr fr a
	y <- replace tr fr b
	return (Either x y)
replace' tr fr (Prod a b) = do
	x <- replace tr fr a
	y <- replace tr fr b
	return (Prod x y)
replace' tr fr (Fun a b) = do
	x <- replace tr fr a
	y <- replace tr fr b
	return (Fun x y)
replace' tr fr (Lns a b) = do
	x <- replace tr fr a
	y <- replace tr fr b
	return (Lns x y)
replace' tr fr (List a) = do
	x <- replace tr fr a
	return (List x)
replace' tr fr (Data s f) = do
	g <- replaceF tr fr f
	Eq <- feq f g
	return (Data s g)
replace' tr fr (NewData s f) = do
	g <- replaceF tr fr f
	return (NewData s g)
replace' tr fr (Pf a) = do
	x <- replace tr fr a
	return (Pf x)
replace' tr fr TP = return TP
replace' tr fr (TU a) = do
	x <- replace tr fr a
	return $ TU a
replace' tr fr Any = return Any
replace' tr fr Dynamic = return Dynamic

replaceF,replaceF' :: TypeRule s -> FctrRule s -> FctrRule s
replaceF tr fr f = fr f `mplus` replaceF' tr fr f
replaceF' tr fr I = return I
replaceF' tr fr (K a) = do
	x <- replace tr fr a 
	return (K x)
replaceF' tr fr L = return L
replaceF' tr fr (f :*!: g) = do
	x <- replaceF tr fr f
	y <- replaceF tr fr g
	return (x :*!: y)
replaceF' tr fr (f :+!: g) = do
	x <- replaceF tr fr f
	y <- replaceF tr fr g
	return (x :+!: y)
replaceF' tr fr (f :@!: g) = do
	x <- replaceF tr fr f
	y <- replaceF tr fr g
	return (x :@!: y)