packages feed

Ztrategic-0.1.0: Language/Memo/Ztrategic.hs

{-# LANGUAGE Rank2Types #-}
{-# OPTIONS_GHC -Wno-unrecognised-pragmas #-}
{-# HLINT ignore "Use camelCase" #-}
module Language.Memo.Ztrategic where

import Language.ZipperAG
import Data.Generics.Zipper hiding (left, right, up, down')
import Data.Generics.Aliases
import Data.Maybe
import Data.Data
import Control.Monad -- (join, mplus, MonadPlus)

import Control.Monad.Trans.Maybe -- for MaybeT in elevate func

import Language.StrategicData
import Language.Memo.AGMemo

----------
----
--- TP
----
----------

newtype TP m = MkTP (forall d mm. (StrategicData (d mm), Memoizable d mm) => Zipper (d mm) -> m (Zipper (d mm)))
unTP (MkTP f) = f

applyTP_clean :: (Monad m, StrategicData (d mm), Memoizable d mm) => TP m -> Zipper (d mm) -> m (Zipper (d mm))
applyTP_clean f = fmap cleanMemoTable . unTP f

applyTP :: (StrategicData (d mm), Memoizable d mm) => TP m -> Zipper (d mm) -> m (Zipper (d mm))
applyTP = unTP

elevate :: (Monad m, Typeable b) => (b -> m b) -> Zipper a -> m (Maybe (Zipper a))
elevate g z = runMaybeT $ transM (MaybeT . maybe (return Nothing) (fmap cast . g) . cast) z


elevateZ :: (Monad m, Typeable a, Typeable b, Typeable c) => (b -> Zipper c -> m (Zipper c)) -> Zipper a -> m (Maybe (Zipper a))
elevateZ f z = maybe (return Nothing) (\b -> maybe (return Nothing) (fmap cast . f b) (cast z)) (getHole z)

full_tdTP :: (Monad m) => TP m  -> TP m
full_tdTP f = f `seqTP` allTPdown (full_tdTP f) `seqTP` allTPright (full_tdTP f)

full_buTP :: (Monad m) => TP m -> TP m
full_buTP f = allTPright (full_buTP f) `seqTP` allTPdown (full_buTP f) `seqTP` f

once_tdTP :: (MonadPlus m) => TP m -> TP m
once_tdTP f = f `choiceTP` oneTPdown (once_tdTP f) `choiceTP` oneTPright (once_tdTP f)

once_buTP :: (MonadPlus m) => TP m -> TP m
once_buTP f = oneTPright (once_buTP f) `choiceTP` oneTPdown (once_buTP f) `choiceTP` f

--Experimental
stop_tdTP :: (MonadPlus m) => TP m -> TP m
stop_tdTP f = f `choiceTP` (allTPdown (stop_tdTP f) `seqTP` allTPright (stop_tdTP f))

--Experimental
stop_buTP :: (MonadPlus m) => TP m -> TP m
stop_buTP f = (allTPdown (stop_tdTP f) `seqTP` allTPright (stop_tdTP f)) `choiceTP` f

adhocTP :: (Monad m, Typeable b) => TP m -> (b -> m b) -> TP m
adhocTP f g = MkTP $ \z -> do
          val <- elevate g z
          maybe (applyTP f z) return val

adhocTPSeq :: (MonadPlus m, Typeable b) => TP m -> (b -> m b) -> TP m
adhocTPSeq f g = MkTP (\z -> do
             val <- elevate g z
             maybe (applyTP f z) (applyTP (tryTP f)) val)
                `choiceTP` f

adhocTPZ :: (Monad m, Typeable a, Typeable b) => TP m -> (b -> Zipper a -> m (Zipper a)) -> TP m
adhocTPZ f g = MkTP $ \z -> do
          val <- elevateZ g z
          maybe (applyTP f z) return val

adhocTPZSeq :: (MonadPlus m, Typeable a, Typeable b) => TP m -> (b -> Zipper a -> m (Zipper a)) -> TP m
adhocTPZSeq f g = MkTP (\z -> do
             val <- elevateZ g z
             maybe (applyTP f z) (applyTP (tryTP f)) val)
                `choiceTP` f

--Identity function
idTP :: Monad m => TP m
idTP = MkTP return


--Failing function
failTP :: MonadPlus m => TP m
failTP = MkTP (const mzero)

allTPright :: (Monad m) => TP m  -> TP m
allTPright f = MkTP $ \z -> moveM right left (return z) (applyTP f) z

allTPdown :: (Monad m) => TP m  -> TP m
allTPdown f = MkTP $ \z -> moveM down' up (return z) (applyTP f) z

oneTPright :: (MonadPlus m) => TP m -> TP m
oneTPright f = MkTP $ moveM right left mzero (applyTP f)

oneTPdown :: (MonadPlus m) => TP m -> TP m
oneTPdown f = MkTP $ moveM down' up mzero (applyTP f)

--Sequential composition, ignores failure
seqTP :: Monad m => TP m -> TP m -> TP m
seqTP f g = MkTP (unTP f `mseq` unTP g)
f `mseq` g =  f >=> g

--Sequential composition, chooses rightmost only if possible
choiceTP :: MonadPlus m => TP m -> TP m -> TP m
choiceTP f g = MkTP (unTP f `mchoice` unTP g)
f `mchoice` g   =  \x -> f x `mplus` g x


--Apply a function, fail the composition if it fails
monoTP :: (MonadPlus m, Typeable b) => (b -> m b) -> TP m
monoTP = adhocTP failTP

--Apply a function with access to the zipper, fail the composition if it fails
monoTPZ :: (MonadPlus m, Typeable a, Typeable b) => (b -> Zipper a -> m (Zipper a)) -> TP m
monoTPZ = adhocTPZ failTP

--Try to apply a zipper function, and apply identity if it fails
tryTP :: MonadPlus m => TP m -> TP m
tryTP s = s `choiceTP` idTP


repeatTP :: MonadPlus m => TP m -> TP m
repeatTP s =  tryTP (s `seqTP` repeatTP s)

innermost :: (MonadPlus m) => TP m -> TP m
innermost s = allTPright (innermost s)
      `seqTP` allTPdown (innermost s)
      `seqTP` tryTP (s `seqTP` innermost s)

innermost' :: (MonadPlus m) => TP m -> TP m
innermost' s  = repeatTP (once_buTP s)

outermost  :: (MonadPlus m) => TP m -> TP m
outermost s = repeatTP (once_tdTP s)

----------
----
--- TU
----
----------


newtype TU m r = MkTU (forall d mm . (StrategicData (d mm), Memoizable d mm) => Zipper (d mm) -> (m r, Zipper (d mm)))
unTU (MkTU f) = f

applyTU_clean :: (Memoizable d mm, StrategicData (d mm)) => TU m r -> Zipper (d mm) -> (m r, Zipper (d mm))
applyTU_clean f z = case unTU f z of
                (r, z1) -> (r, cleanMemoTable z1)

applyTU :: (Memoizable d mm, StrategicData (d mm)) => TU m r -> Zipper (d mm) -> (m r, Zipper (d mm))
applyTU = unTU

foldr1TU :: (Memoizable d mm, StrategicData (d mm), Monoid (m r), Foldable m, MonadPlus m) =>
    TU m r ->
    Zipper (d mm) -> (r -> r -> r) -> r
foldr1TU f z red = foldr1 red $ fst (applyTU (full_tdTU f) z)

foldl1TU :: (Memoizable d mm, StrategicData (d mm), Monoid (m r), Foldable m, MonadPlus m) =>
    TU m r ->
    Zipper (d mm) -> (r -> r -> r) -> r
foldl1TU f z red = foldl1 red $ fst (applyTU (full_tdTU f) z)

foldrTU :: (Memoizable d mm, StrategicData (d mm), Monoid (m r), Foldable m, MonadPlus m) =>
    TU m r ->
    Zipper (d mm) -> (r -> s -> s) -> s -> s
foldrTU f z red i = foldr red i $ fst (applyTU (full_tdTU f) z)

foldlTU :: (Memoizable d mm, StrategicData (d mm), Monoid (m r), Foldable m, MonadPlus m) =>
    TU m r ->
    Zipper (d mm) -> (s -> r -> s) -> s -> s
foldlTU f z red i = foldl red i $ fst (applyTU (full_tdTU f) z)

full_tdTU :: (MonadPlus m, Monoid (m r)) => TU m r -> TU m r
full_tdTU f = allTUright (full_buTU f) `seqTU` allTUdown (full_buTU f) `seqTU` f

full_buTU :: (MonadPlus m, Monoid (m r)) => TU m r -> TU m r
full_buTU f = f `seqTU` allTUdown (full_tdTU f) `seqTU` allTUright (full_tdTU f)

once_tdTU :: (MonadPlus m, Monoid (m r)) => TU m r -> TU m r
once_tdTU f = f `choiceTU` allTUdown (once_tdTU f)  `choiceTU` allTUright (once_tdTU f)

once_buTU :: (MonadPlus m, Monoid (m r)) => TU m r -> TU m r
once_buTU f = allTUright (once_buTU f) `choiceTU` allTUdown (once_buTU f) `choiceTU` f

stop_tdTU :: (MonadPlus m, Monoid (m r)) => TU m r -> TU m r
stop_tdTU f = (f `choiceTU` allTUdown (stop_tdTU f)) `seqTU` allTUright (stop_tdTU f)

stop_buTU :: (MonadPlus m, Monoid (m r)) => TU m r -> TU m r
stop_buTU f = allTUright (stop_buTU f) `seqTU` (allTUdown (stop_buTU f) `choiceTU` f)


allTUdown :: (Monoid (m r)) => TU m r -> TU m r
allTUdown f = MkTU $ \z -> moveQ down' (mempty, z) (back . applyTU f) z
 where back (a,b) = (a, fromJust $ up b)


allTUright :: (Monoid (m r)) => TU m r -> TU m r
allTUright f = MkTU $ \z -> moveQ right (mempty, z) (back . applyTU f) z
 where back (a,b) = (a, fromJust $ left b)


adhocTU :: (Monad m, Typeable a) => TU m r -> (a -> m r) -> TU m r
adhocTU f g = MkTU $ \z -> maybe (applyTU f z) (\c -> (c, z)) (getHole z >>= return . g)

adhocTUZ :: (Monad m, Typeable a, Typeable d, Typeable mm) => TU m r -> (a -> Zipper (d mm) -> (m r, Zipper (d mm))) -> TU m r
adhocTUZ f g = MkTU $ \z -> fromMaybe (applyTU f z) (reduce g z)

reduce :: (Typeable a, Typeable d, Typeable d', Typeable mm', Typeable mm) => (a -> Zipper (d' mm') -> (m r, Zipper (d' mm'))) -> Zipper (d mm) -> Maybe (m r, Zipper (d mm))
reduce f z = getHole z >>= \v -> cast z >>= (\(r, m) -> cast m >>= \mc -> return (r, mc)) . f v

seqTU :: (Monoid (m r)) => TU m r -> TU m r -> TU m r
seqTU x y = MkTU $ \z ->
  let (yr, z') = applyTU y z
      (xr, z'') = applyTU x z'
  in (xr `mappend` yr, z'')

choiceTU :: (MonadPlus m) => TU m r -> TU m r -> TU m r
choiceTU x y = MkTU $ \z ->
  let (yr, z') = applyTU y z
      (xr, z'') = applyTU x z'
  in (xr `mplus` yr, z'')


failTU :: (MonadPlus m) => TU m r
failTU = MkTU $ \z -> (mzero, z)

constTU :: Monad m => r -> TU m r
constTU v = MkTU $ \z -> (return v, z)

--Apply a function, fail the composition if it fails
monoTU :: (MonadPlus m, Typeable a) => (a -> m r) -> TU m r
monoTU = adhocTU failTU

--Apply a function with access to the zipper, fail the composition if it fails
monoTUZ :: (MonadPlus m, Typeable a, Typeable d, Typeable mm) => (a -> Zipper (d mm) -> (m r, Zipper (d mm))) -> TU m r
monoTUZ = adhocTUZ failTU