{----------------------------------------------------------------------------- A model of functional strategies using Data.Generics as of >= GHC 6.2. (The version of Data.Generics as of GHC 6.0 is not applicable here.) Strategy application, strategy update, and traversal are different from the original Strafunski model. Most other combinators (seqT?, ...) are retained as is. -----------------------------------------------------------------------------} module Data.Generics.Strafunski.StrategyLib.Models.Deriving.StrategyPrimitives ( Term, TP, TU, 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 Data.Generics.Strafunski.StrategyLib.Models.Deriving.TermRep import Data.Generics import Control.Monad import Data.Monoid import Data.Generics.Strafunski.StrategyLib.MonadicFunctions import Control.Monad.Run --- Strategy representation -------------------------------------------------- newtype Monad m => TP m = MkTP (forall x. Data x => x -> m x) newtype Monad m => TU a m = MkTU (forall x. Data x => x -> m a) unTP (MkTP f) = f 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, Data x) => TP m -> x -> m x applyTP = unTP applyTU :: (Monad m, Data x) => TU a m -> x -> m a applyTU = unTU --- Strategy update ---------------------------------------------------------- adhocTP :: (Monad m, Data t) => TP m -> (t -> m t) -> TP m adhocTP s f = MkTP (unTP s `extM` f) adhocTU :: (Monad m, Data t) => TU a m -> (t -> m a) -> TU a m adhocTU s f = MkTU (unTU s `extQ` f) --- 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 = MkTP (gmapM (applyTP s)) -- Succeed for one child; don't care about the other children oneTP :: MonadPlus m => TP m -> TP m oneTP s = MkTP (gmapMo (applyTP s)) -- Succeed for as many children as possible anyTP :: MonadPlus m => TP m -> TP m anyTP s = allTP (s `choiceTP` paraTP return) -- Succeed for as many children as possible but at least for one someTP :: MonadPlus m => TP m -> TP m someTP s = MkTP (gmapMp (applyTP s)) -- Simulate injection injTP :: MonadPlus m => TP m -> TP m injTP s = (MkTU (return . glength)) `passTP` (\x -> if x == 1 then allTP s else paraTP (const mzero)) -- Type-unifying allTU :: Monad m => (a -> a -> a) -> a -> TU a m -> TU a m allTU op2 u s = MkTU (\x -> fold (gmapQ (applyTU s) x)) where fold l = foldM op2' u l op2' x c = c >>= \y -> return (x `op2` y) 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 = MkTU (\x -> fold (gmapQ (applyTU s) x)) where fold [] = mzero fold (h:t) = (h >>= \x -> return x) `mplus` fold t anyTU :: MonadPlus m => (a -> a -> a) -> a -> TU a m -> TU a m anyTU op2 u s = allTU op2 u (s `choiceTU` paraTU (const (return 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 = MkTU (\x -> fold False (gmapQ (applyTU s) x)) where fold False [] = mzero fold True [] = return u fold b (h:t) = (h >>= \x -> fold True t >>= \y -> return (x `op2` y)) `mplus` fold b t someTU' :: (Monoid a, MonadPlus m) => TU a m -> TU a m someTU' = someTU mappend mempty