packages feed

lambdabot-4.1: scripts/FT/FreeTheorems/Reduction.hs

-- Copyright 2006, Sascha Boehme.




-- | This module contains a function to reduce automatically generated
--   relations.

module FreeTheorems.Reduction (
    reduceRelation,

    -- testing interface
    -- testReduction
) where



import FreeTheorems.Types

-- import FreeTheorems.Test.ArbitraryTypes
-- import Test.QuickCheck (quickCheck)



-- | Simplifies relations by replacing lifted relations by identity relations
--   if possible. A lifted relation can be reduced to an identity relation, if
--   all relations it is based on are identity relations. The same is true for
--   functional relations.

reduceRelation :: Relation -> Relation
reduceRelation rel = either id toIdentityRelation $ reduceToId rel



-- | Reduces relations to identity relations. This is a helper function for
--   'reduceRelation'.
--
--   If a lifted relation is only based on identity relations, it can be
--   replaced by a identity relation itself. The same is true for functional
--   relations.
--
--   This functions walks other a given relation and decides on this mechanism
--   if a lifted function should be reduced. It returns @Right t@ if the
--   relation @r@ was reduced to an identity over type @t@. Otherwise,
--   @Left r'@ is returned, where @r'@ is the relation @r@ with possible changes
--   in its subrelations.

reduceToId :: Relation -> Either Relation Type
reduceToId rel =
  case rel of
    RelTerm term typepair   -> processTerm term typepair
    RelVar rv               -> Left rel
    RelLift model con rels  -> either (Left . RelLift model con)
                                      (Right . TypeCon con)
                                      (foldReduceToId rels)

    RelLiftList model rel'  -> either (Left . RelLiftList model)
                                      (Right . TypeList)
                                      (reduceToId rel')

    RelLiftTuple model rels -> either (Left . RelLiftTuple model)
                                      (Right . TypeTuple)
                                      (foldReduceToId rels)

    RelFun model rel1 rel2  -> either (\[r1,r2] -> Left $ RelFun model r1 r2)
                                      (\[t1,t2] -> Right $ TypeFun t1 t2)
                                      (foldReduceToId [rel1, rel2])

    RelForall model rv rel' -> either (Left . RelForall model rv)
                                      (Left . RelForall model rv
                                       . toIdentityRelation)
                                      (reduceToId rel')

  where
    processTerm term typepair =
      case term of
        TermIns (TermVar (PV "id")) ty -> Right ty
        otherwise                      -> Left (RelTerm term typepair)

    foldReduceToId = foldr (\r x -> combine (reduceToId r) x) (Right [])

    combine (Left x) (Left es)   = Left (x : es)
    combine (Left x) (Right es)  = Left (x : (map toIdentityRelation es))
    combine (Right x) (Left es)  = Left ((toIdentityRelation x) : es)
    combine (Right x) (Right es) = Right (x : es)



-- | Returns the identity relation for a given type.

toIdentityRelation :: Type -> Relation
toIdentityRelation t = RelTerm (TermIns (TermVar (PV "id")) t) (t,t)



--------------------------------------------------------------------------------



-- A list of tests for this module.

{-
testReduction = do
  putStr "reduction of relation works ... "
  quickCheck prop_reduceRelation



-- Check that 'simplifyRelationsToId' doesn't change anything when applied
-- twice and that it preserves the structure.

prop_reduceRelation rel =
  (reduceRelation (reduceRelation rel) == reduceRelation rel)
  && compareRelAndRel ((reduceRelation rel), rel)

compareRelAndRel pair =
  case pair of
    (RelTerm t1 _, RelTerm t2 _) -> t1 == t2
    (RelTerm t1 _, _)            -> True

    (RelVar rv1, RelVar rv2) -> rv1 == rv2

    (RelLift m1 c1 rels1, RelLift m2 c2 rels2) ->
        (m1 == m2) && (c1 == c2) && and (map compareRelAndRel $ zip rels1 rels2)

    (RelLiftList m1 rel1, RelLiftList m2 rel2) ->
        (m1 == m2) && compareRelAndRel (rel1, rel2)

    (RelLiftTuple m1 rels1, RelLiftTuple m2 rels2) ->
        (m1 == m2) && and (map compareRelAndRel $ zip rels1 rels2)

    (RelFun m1 rel1 rel1', RelFun m2 rel2 rel2') ->
        (m1 == m2) && compareRelAndRel (rel1, rel2)
                   && compareRelAndRel (rel1', rel2')

    (RelForall m1 rv1 rel1, RelForall m2 rv2 rel2) ->
        (m1 == m2) && (rv1 == rv2) && compareRelAndRel (rel1, rel2)

    otherwise -> False

-}