packages feed

HaRe-0.6: StrategyLib-4.0-beta/models/drift-default/StrategyPrimitives.hs

{-----------------------------------------------------------------------------

 	          A LIBRARY OF FUNCTIONAL STRATEGY COMBINATORS

		                  StrategyLib

                   Ralf Laemmel                Joost Visser
               CWI & VU, Amsterdam         CWI & SIG, Amsterdam

This module is part of a library of functional strategy combinators,
including combinators for generic traversal. The generic function
representation that relies on a universal term representation is
defined in this module. The safety of the generic function combinators
is guaranteed by not exporting the data constructor MkTP.

-----------------------------------------------------------------------------} 

module StrategyPrimitives (

  Term,
  TP,         TU,       -- Note: MkTP is not exported, MkTU could be exported
  paraTP,     paraTU,
  applyTP,    applyTU,
  adhocTP,    adhocTU,
  msubstTP,   msubstTU,
  seqTP,      seqTU,
  passTP,     passTU,
  choiceTP,   choiceTU,
  mchoicesTP, mchoicesTU,
  allTP,      allTU, allTU',
  oneTP,      oneTU,
  anyTP,      anyTU, anyTU',
  someTP,     someTU, someTU',
  injTP

) where

import TermRep
import Monad
import Data.Monoid
import MonadicFunctions
import MonadRun


--- Strategy representation --------------------------------------------------

newtype TP m  	 = MkTP (TermRep -> m TermRep)
newtype TU a m	 = MkTU (TermRep -> m a)

unTP 		:: TP m -> TermRep -> m TermRep
unTP (MkTP f)	 = f

unTU 		:: TU a m -> TermRep -> m a
unTU (MkTU f)	 = f


--- Parametricially polymorphic strategies -----------------------------------

paraTP 		:: Monad m => (forall t. t -> m t) -> TP m
paraTP f	=  MkTP f

paraTU 		:: Monad m => (forall t. t -> m a) -> TU a m
paraTU f	=  MkTU f


--- Strategy application -----------------------------------------------------

applyTP 	:: (Monad m, Term t) => TP m -> t -> m t
applyTP s t	=  do { t' <- unTP s (explode t); return (implode t') }

applyTU 	:: (Monad m, Term t) => TU a m -> t -> m a
applyTU s t	=  unTU s (explode t)

applyOnKids 	:: Monad m => ([TermRep] -> m [TermRep]) -> TP m
applyOnKids s	=  MkTP (\ t -> s (getChildren t) >>= \ks' ->
                                return (getConstr t ks'))

applyOnKidsTU 	:: ([TermRep] -> m a) -> TU a m
applyOnKidsTU s	=  MkTU (\ t -> s (getChildren t))



--- Strategy update ----------------------------------------------------------

adhocTP 	:: (Monad m, Term t) => TP m -> (t -> m t) -> TP m
adhocTP s f	=  MkTP (\u -> if applicable f u 
                               then do t <- f (implode u)
                                       return (explode t)
                               else (unTP s u) )

adhocTU	 	:: (Monad m, Term t) => TU a m -> (t -> m a) -> TU a m
adhocTU s f	=  MkTU (\u -> if applicable f u
                               then (f (implode u))
                               else (unTU s u) )


applicable 	:: Typeable a => (a -> b) -> TermRep -> Bool
applicable f u  =  case u `hasTypeOf` (undefined `withArgType` f) of
                     Just _  -> True
		     Nothing -> False
                   where withArgType :: a -> (a -> x) -> a
                         withArgType a f = a

-- Applicability of a monomorphic function to a universal term representation
-- is defined by comparing the type representation of the argument type of the
-- function with the type representation of the term representation at hand.


--- Effect manipulation ------------------------------------------------------

                                               -- Replace one monad by another
					       
msubstTP	:: (Monad m, Monad m') 
		=> (forall t . m t -> m' t) -> TP m -> TP m'
msubstTP e f	=  MkTP (\x -> e ((unTP f) x))

msubstTU	:: (Monad m, Monad m') 
		=> (m a -> m' a) -> TU a m -> TU a m'
msubstTU e f	=  MkTU (\x -> e ((unTU f) x))



--- Deterministic combinators ------------------------------------------------

    -- Type-preserving

seqTP 		:: Monad m => TP m -> TP m -> TP m
seqTP f g 	=  MkTP ((unTP f) `mseq` (unTP g))

passTP 		:: Monad m => TU a m -> (a -> TP m) -> TP m
passTP f g 	=  MkTP ((unTU f) `mlet` (\y -> unTP (g y)))

    -- Type-unifying

seqTU 		:: Monad m => TP m -> TU a m -> TU a m
seqTU f g	=  MkTU ((unTP f) `mseq` (unTU g))

passTU 		:: Monad m => TU a m -> (a -> TU b m) -> TU b m
passTU f g	=  MkTU ((unTU f) `mlet` (\y -> unTU (g y))) 


--- Combinators for partiality and non-determinism ---------------------------

    -- Type-preserving

choiceTP 	:: MonadPlus m => TP m -> TP m -> TP m
choiceTP f g	=  MkTP ((unTP f) `mchoice` (unTP g))

    -- Type-unifying

choiceTU 	:: MonadPlus m => TU a m -> TU a m -> TU a m
choiceTU f g	=  MkTU ((unTU f) `mchoice` (unTU g))

-- With localization of partiality:

mchoicesTP fs f		=  MkTP (\a -> mchoices (map unTP fs) (unTP f) a)

mchoicesTU fs f		=  MkTU (\a -> mchoices (map unTU fs) (unTU f) a)


--- Traversal combinators ----------------------------------------------------

    -- Type-preserving

-- Succeed for all children
allTP 		:: Monad m => TP m -> TP m
allTP s		=  applyOnKids (mapM (unTP s))

-- Succeed for one child; don't care about the other children
oneTP 		:: MonadPlus m => TP m -> TP m
oneTP s		=  applyOnKids (oneM (unTP s))

-- Succeed for as many children as possible
anyTP 		:: MonadPlus m => TP m -> TP m
anyTP s		=  applyOnKids (anyM (unTP s))

-- Succeed for as many children as possible but at least for one
someTP	 	:: MonadPlus m => TP m -> TP m
someTP s	=  applyOnKids (someM (unTP s))

-- Simulate injection
injTP           :: MonadPlus m => TP m -> TP m     
injTP s         =  MkTP (\t -> 
                          case (getChildren t) of 
                           [k] -> unTP s k >>= \k' ->
                                  return (getConstr t [k'])
                           _ -> mzero)                                  

    -- Helpers

oneM f []	= mzero
oneM f (x:xs)	= do { x' <- (f x); return (x':xs) }
                  `mplus`
		  do { xs' <- oneM f xs; return (x:xs') }

uniM f []	= mzero
uniM f (x:xs)	= do { x' <- (f x); () <- noneV f xs; return (x':xs) }
		  `mplus`
		  do { () <- noneV f [x]; xs' <- uniM f xs; return (x:xs') }

noneV f []	= return ()
noneV f (x:xs)  = ((f x >>= \_ -> return True) `mplus` (return False))
                  >>= \b -> if b then mzero
                                 else noneV f xs

anyM f []	= return []
anyM f (x:xs)	= do x'  <- ((f x) `mplus` (return x))
                     xs' <-  anyM f xs
                     return (x':xs')

someM f []	= mzero
someM f (x:xs)	= do { x'  <- f x; xs' <- anyM f xs; return (x':xs') }
                  `mplus`
                  do { xs' <- someM f xs; return (x:xs') }

    -- Type-unifying

allTU 		:: Monad m => (a -> a -> a) -> a -> TU a m -> TU a m
allTU op2 u s   =  applyOnKidsTU (foldM cons u)
		     where cons i c = do c' <- (unTU s c)
		                         return (i `op2` c')

allTU' 		:: (Monad m, Monoid a) => TU a m -> TU a m
allTU'		=  allTU mappend mempty

oneTU 		:: MonadPlus m => TU a m -> TU a m
oneTU s		=  applyOnKidsTU (foldr cons mzero)
		   where cons c i = (unTU s c) `mplus` i

anyTU		:: MonadPlus m => (a -> a -> a) -> a -> TU a m -> TU a m
anyTU op2 u s	=  applyOnKidsTU (foldM (anyTUcons op2 (unTU s)) u)

anyTU'		:: (MonadPlus m, Monoid a) => TU a m -> TU a m
anyTU' 		=  anyTU mappend mempty

someTU	 	:: MonadPlus m => (a -> a -> a) -> a -> TU a m -> TU a m
someTU op2 u s	=  applyOnKidsTU (someTUfold op2 u (unTU s))

someTU'	 	:: (Monoid a, MonadPlus m) => TU a m -> TU a m
someTU'		=  someTU mappend mempty


    -- Helpers

anyTUcons op2 f i c
  = do { c' <- f c; return (i `op2` c') }
       `mplus`
       return i

someTUfold op2 u f [] = mzero
someTUfold op2 u f (x:xs)
	= do c <- f x
             i <- (foldM (anyTUcons op2 f) u) xs
             return (i `op2` c)
             `mplus`
             someTUfold op2 u f xs


--- Illustration of type safety ----------------------------------------------

-- The safety of this model of strategies relies on hiding of MkTP. The
-- following term demonstrates unsafe use of the MkTP constructor. We catch a
-- universal representation which arose from a string and we throw it in for
-- the result of a type-preserving function. Clearly, if we attempt to apply
-- the inner type-preserving strategy to a Boolean constant, then we end up
-- with an implosion error.

brokenTerm	 = applyTU 
                     (MkTU (\u -> applyTP (MkTP (const (Just u))) True)) 
                     "BREAK"

-- If the paraTP constructor function is used instead, the resulting term
-- is not typable:
--
-- untypableTerm = applyTU 
--                  (MkTU (\u -> applyTP (paraTP (const (return u))) True)) 
--                  "BREAK"
--
-- Thus, by not exporting MkTP, safety is guaranteed.

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