packages feed

Eq-1.0: EqManips/FormulaIterator.hs

{-# LANGUAGE ScopedTypeVariables #-}
module EqManips.FormulaIterator( depthFirstFormula
                               , depthFormulaTraversal 
                               , depthFormulaPrimTraversal 
                               , depthPrimTraversal 
                               , topDownTraversal 
                               , topDownScanning 
                               ) where

import Control.Applicative
import Control.Monad.Identity
import EqManips.Types

import EqManips.EvaluationContext

-- | Depth first traversal of formula.
-- the function is applied to each subformula when
-- the traversal is coming back to the top of the
-- formula tree.
depthFirstFormula :: (Applicative m, Monad m) 
                  => (Formula a -> m (Formula b)) -> Formula a -> m (Formula b)
depthFirstFormula = depthFormulaTraversal . const $ return ()

depthFormulaTraversal :: (Applicative m, Monad m)
                      => (Formula a -> m ())
                      -> (Formula a -> m (Formula b))
                      -> Formula a -> m (Formula b)
depthFormulaTraversal pre f formula = do
    prim <- depthPrimTraversal
                      (pre . Formula)
                      -- Can't get it to compile with >>= or <$>
                      -- so back to ugly form
                      (\a -> do a' <- f $ Formula a
                                return $ unTagFormula a')
                      $ unTagFormula formula
    return $ Formula prim


depthFormulaPrimTraversal :: (Applicative m, Monad m)
                          => (FormulaPrim -> m FormulaPrim)
                          -> FormulaPrim
                          -> m FormulaPrim
depthFormulaPrimTraversal = depthPrimTraversal (const $ return ())

topDownTraversal :: (FormulaPrim -> Maybe FormulaPrim)
                 -> FormulaPrim -> FormulaPrim
topDownTraversal f formu =
    runIdentity $ topDownScanning (return . f) formu

fromMaybeM :: (Monad m) => m a -> m (Maybe a) -> m a
fromMaybeM e da = do
    rez <- da
    case rez of
         Nothing -> e
         Just a  -> return a

-- | This function must be used to transform function from
-- the top.
{-# SPECIALIZE topDownScanning :: (FormulaPrim -> Identity (Maybe FormulaPrim))
                               -> FormulaPrim -> Identity FormulaPrim #-}
{-# SPECIALIZE topDownScanning :: (FormulaPrim -> EqContext (Maybe FormulaPrim))
                               -> FormulaPrim -> EqContext FormulaPrim #-}
topDownScanning :: (Monad m, Applicative m)
                => (FormulaPrim -> m (Maybe FormulaPrim))
                -> FormulaPrim
                -> m FormulaPrim
topDownScanning f p@(Poly _ _) = fromMaybeM (return p) $ f p
topDownScanning f v@(Variable _) = fromMaybeM (return v) $ f v
topDownScanning f i@(CInteger _) = fromMaybeM (return i) $ f i
topDownScanning f i@(Fraction _) = fromMaybeM (return i) $ f i
topDownScanning f i@(Complex _ _) = fromMaybeM (return i) $ f i
topDownScanning f d@(CFloat _) = fromMaybeM (return d) $ f d
topDownScanning f e@(NumEntity _) = fromMaybeM (return e) $ f e
topDownScanning f t@(Truth _) = fromMaybeM (return t) $ f t
topDownScanning f l@(Lambda _ eqs) = 
    fromMaybeM (lambda <$> lambda') $ f l
        where lambda' = sequence
                  [ do args' <- mapM (topDownScanning f) args
                       body' <- topDownScanning f body
                       return (args', body') | (args, body) <- eqs]

topDownScanning f met@(Meta _ op form) =
    fromMaybeM (meta op <$> topDownScanning f form) $ f met

topDownScanning f i@(Indexes _ what lst) = do
    what' <- topDownScanning f what
    fromMaybeM (indexes what' <$> mapM (topDownScanning f) lst)
                 $ f i

topDownScanning f l@(List _ lst) =
    fromMaybeM (list <$> mapM (topDownScanning f) lst) $ f l

topDownScanning f formula@(App _ func args) =
    fromMaybeM (app <$> mayFunc <*> mayArgs) $ f formula
        where mayFunc = topDownScanning f func
              mayArgs = mapM (topDownScanning f) args

topDownScanning f formula@(Sum _ ini end what) =
    fromMaybeM (summ <$> mayIni <*> mayEnd <*> mayWhat) $ f formula
        where mayIni = topDownScanning f ini
              mayEnd = topDownScanning f end
              mayWhat = topDownScanning f what

topDownScanning f formula@(Product _ ini end what) =
    fromMaybeM (productt <$> mayIni <*> mayEnd <*> mayWhat) $ f formula
        where mayIni = topDownScanning f ini
              mayEnd = topDownScanning f end
              mayWhat = topDownScanning f what

topDownScanning f formula@(Derivate _ what var) =
    fromMaybeM (derivate <$> mayWhat <*> mayVar ) $ f formula
        where mayVar = topDownScanning f var
              mayWhat = topDownScanning f what

topDownScanning f formula@(Integrate _ ini end what var) =
    fromMaybeM (integrate <$> mayIni <*> mayEnd <*> mayWhat <*> mayVar) $ f formula
        where mayIni = topDownScanning f ini
              mayEnd = topDownScanning f end
              mayWhat = topDownScanning f what
              mayVar = topDownScanning f var

topDownScanning f formula@(Matrix _ n m cells) =
    fromMaybeM (matrix n m <$> mapM (mapM (topDownScanning f)) cells)
            $ f formula

topDownScanning f formula@(UnOp _ op sub) =
    fromMaybeM (unOp op <$> topDownScanning f sub) $ f formula

topDownScanning f formula@(BinOp _ op fs) =
    fromMaybeM (binOp op <$> mapM (topDownScanning f) fs) $ f formula

-- Hmm, it's a debug for renderer, we dont really care
topDownScanning _ b@(Block _ _ _) = return b


-- | Depth first traversal providing two events :
-- - One pre event which is called when a node is
--   reached when descending the tree
-- - One post event similar to depthFirstFormula,
--   reached when the traversal go up.
-- Note : the leaf don't have a pre event, just a
--        post.
{-# SPECIALIZE depthPrimTraversal :: (FormulaPrim -> Identity ())
                                  -> (FormulaPrim -> Identity FormulaPrim)
                                  -> FormulaPrim -> Identity FormulaPrim #-}
{-# SPECIALIZE depthPrimTraversal :: (FormulaPrim -> EqContext ())
                                  -> (FormulaPrim -> EqContext FormulaPrim)
                                  -> FormulaPrim -> EqContext FormulaPrim #-}
depthPrimTraversal :: (Applicative m, Monad m) 
                   => (FormulaPrim -> m ()) 
                   -> (FormulaPrim -> m FormulaPrim)
                   -> FormulaPrim
                   -> m FormulaPrim
depthPrimTraversal _ f p@(Poly _ _) = f p
depthPrimTraversal _ f v@(Variable _) = f v
depthPrimTraversal _ f i@(CInteger _) = f i
depthPrimTraversal _ f i@(Fraction _) = f i
depthPrimTraversal _ f d@(CFloat _) = f d
depthPrimTraversal _ f e@(NumEntity _) = f e
depthPrimTraversal _ f t@(Truth _) = f t
depthPrimTraversal pre f i@(Indexes _ main lst) = do
    pre i
    main' <- depthPrimTraversal pre f main
    lst' <- mapM (depthPrimTraversal pre f) lst
    f $ indexes main' lst'

depthPrimTraversal pre f i@(List _ lst) = do
    pre i
    lst' <- mapM (depthPrimTraversal pre f) lst
    f $ list lst'

depthPrimTraversal pre f c@(Complex _ (r, i)) = do
    pre c
    r' <- depthPrimTraversal pre f r
    i' <- depthPrimTraversal pre f i
    f $ complex (r', i')

depthPrimTraversal pre f l@(Lambda _ eqs) = do
	pre l
	f =<< lambda <$> mapM traverser eqs
		where traverser (args, body) = do
				body' <- depthPrimTraversal pre f body
				return (args, body')

depthPrimTraversal pre post met@(Meta _ op f) = do
    pre met
    post =<< meta op <$> depthPrimTraversal pre post f

depthPrimTraversal pre post formula@(App _ func args) = do
    pre formula
    post =<< app <$> depthPrimTraversal pre post func
                 <*> mapM (depthPrimTraversal pre post) args

depthPrimTraversal pre post formula@(Sum _ ini end what) = do
    pre formula
    post =<< summ <$> depthPrimTraversal pre post ini
                  <*> depthPrimTraversal pre post end
                  <*> depthPrimTraversal pre post what

depthPrimTraversal pre post formula@(Product _ ini end what) = do
    pre formula
    post =<< productt <$> depthPrimTraversal pre post ini
                      <*> depthPrimTraversal pre post end
                      <*> depthPrimTraversal pre post what

depthPrimTraversal pre post formula@(Derivate _ what var) = do
    pre formula
    post =<< derivate <$> depthPrimTraversal pre post what
                      <*> depthPrimTraversal pre post var

depthPrimTraversal pre post formula@(Integrate _ ini end what var) = do
    pre formula
    post =<< integrate 
        <$> depthPrimTraversal pre post ini
        <*> depthPrimTraversal pre post end
        <*> depthPrimTraversal pre post what
        <*> depthPrimTraversal pre post var

depthPrimTraversal pre post formula@(Matrix _ n m cells) = do
    pre formula
    post =<< matrix n m
         <$> sequence [ mapM (depthPrimTraversal pre post) matrixLine
                            | matrixLine <- cells]

depthPrimTraversal pre post formula@(UnOp _ op sub) = do
    pre formula
    post =<< unOp op <$> depthPrimTraversal pre post sub

depthPrimTraversal pre post formula@(BinOp _ op fs) = do
    pre formula
    post =<< binOp op <$> mapM (depthPrimTraversal pre post) fs

-- Hmm, it's a debug for renderer, we dont really care
depthPrimTraversal _ _ b@(Block _ _ _) = return b