packages feed

compdata-0.8: examples/Examples/Automata/MHom.hs

{-# LANGUAGE RankNTypes, MultiParamTypeClasses, FlexibleInstances,
  FlexibleContexts, UndecidableInstances, TypeOperators,
  ImplicitParams, GADTs, IncoherentInstances, ScopedTypeVariables,
  TupleSections #-}
--------------------------------------------------------------------------------
-- |
-- Module      :  Examples.MHom
-- Copyright   :  (c) 2011 Patrick Bahr
-- License     :  BSD3
-- Maintainer  :  Patrick Bahr <paba@diku.dk>
-- Stability   :  experimental
-- Portability :  non-portable (GHC Extensions)
--
--
--------------------------------------------------------------------------------

module Examples.Automata.MHom
    ( module Examples.Automata.MHom
    , module Data.Stream ) where

import Data.Comp.Zippable
import Data.Comp
import Data.Comp.Ops
import Data.Stream (Stream(..), (<:>))
import Data.Comp.Show ()
import Data.Map (Map)
import qualified Data.Map as Map
import Control.Monad
import Control.Arrow (first, (&&&))
import Data.Comp.Derive

-- | An instance @a :< b@ means that @a@ is a component of @b@. @a@
-- can be extracted from @b@ via the method 'ex'.
class p :< q where
    pr :: q a -> p a
    up :: p a -> q a -> q a

instance q :< q where
    pr = id
    up = const

instance p :< p :*: q where
    pr = ffst
    up x (_ :*: y) = x :*: y

instance (p :< q) => p :< (p' :*: q) where
    pr = pr . fsnd
    up  y (x :*: y') = x :*: up y y'

-- | This function provides access to components of the states from
-- "below".
below :: (?below :: i -> q a, p :< q) => i -> p a
below = pr . ?below

-- | This function provides access to components of the state from
-- "above"
above :: (?above :: q a, p :< q) => p a
above = pr ?above

hole :: (?get :: i -> a) => i -> Context f a
hole = Hole . ?get

-- | Turns the explicit parameters @?above@ and @?below@ into explicit
-- ones.
explicit :: q a -> (i -> q a) -> (i -> a)
         -> ((?get :: i -> a, ?below :: i -> q a, ?above :: q a) => b) -> b
explicit ab bel get x = x
    where ?above = ab
          ?below = bel
          ?get = get
-- | This type represents generalised term homomorphisms. Generalised
-- term homomorphisms have access to a state that is provided
-- (separately) by a DUTA or a DDTA (or both).
type MHom q f g = forall a i . (?get :: i -> a, ?below :: i -> q a, ?above :: q a)
    => f i -> Context g a


-- | This type represents transition functions of deterministic
-- bottom-up tree transducers (DUTTs).

type UpTrans q f g = forall a. f (q a,a) -> (q (Context g a), Context g a)

-- | This function transforms DUTT transition function into an
-- algebra.
upAlg :: (Functor g, Functor q)  => UpTrans q f g -> Alg f (q (Term g), Term g)
upAlg trans t = let (q , c) = trans t
                in (fmap appCxt q, appCxt c)


-- | This function runs the given DUTT on the given term.

runUpTrans :: (Functor f, Functor g, Functor q) => UpTrans q f g -> Term f -> (q (Term g), Term g)
runUpTrans = cata . upAlg

-- | This function generalises 'runUpTrans' to contexts. Therefore,
-- additionally, a transition function for the holes is needed.
runUpTrans' :: (Functor f, Functor g, Functor q)
            => UpTrans q f g -> Context f (q a,a) -> (q (Context g a), Context g a)
runUpTrans' trans = run where
    run (Hole (q,a)) = (fmap Hole q, Hole a)
    run (Term t) = let (q, c) = trans $ fmap run t
                   in (fmap appCxt q, appCxt c)

-- | This function composes two DUTTs. (I'm not sure whether it is correct, yet.)
compUpTrans :: (Functor f, Functor g, Functor h, Functor q1, Functor q2)
               => UpTrans q2 g h -> UpTrans q1 f g -> UpTrans (q1 :*: q2) f h
compUpTrans t2 t1 x = (q1' :*: q2, c2) where
    (q1, c1) = t1 $ fmap shuffle  x
    shuffle (q1 :*: q2,a) = (fmap (q2,) q1 ,(q2,a) )
    q1' = fmap (snd . runUpTrans' t2) q1
    (q2, c2) = runUpTrans' t2 c1

-- | This type represents transition functions of deterministic
-- bottom-up tree acceptors (DUTAs).
type UpState f q = forall a . f (q a, a) -> q a

-- | This combinator runs the given DUTA on a term returning the final
-- state of the run.
runUpState :: (Functor f) => UpState f q -> Term f -> q (Term f)
runUpState st = run where
    run (Term t) = st $ fmap (\ s -> (run s, s)) t


-- | This function combines the product DUTA of the two given DUTAs.
prodUpState :: Functor f => UpState f p -> UpState f q -> UpState f (p :*:q)
prodUpState sp sq t = p :*: q where
    p = sp $ fmap (first ffst) t
    q = sq $ fmap (first fsnd) t

-- | This function turns constructs a DUTT from a given macro term
-- homomorphism with the state propagated by the given DUTA.
toUpTrans :: (Functor f, Functor g, Functor q)
          => UpState f q -> MHom q f g -> UpTrans q f g
toUpTrans st f t = (fmap Hole q, c)
    where q = st t
          c = explicit q (pr . fst) snd f t

-- | This function applies a given generalised term homomorphism with
-- a state space propagated by the given DUTA to a term.
upHom :: (Functor f, Functor g, Functor q) => UpState f q -> MHom q f g -> Term f -> (q (Term g),Term g)
upHom alg h = runUpTrans (toUpTrans alg h)

-- | This type represents transition functions of generalised
-- deterministic bottom-up tree acceptors (GDUTAs) which have access
-- to an extended state space.
type GUpState f q p = forall a i . (?get :: i -> a, ?below :: i -> p a, ?above :: p a, q :< p) => f i -> q a

-- | This combinator turns an arbitrary DUTA into a GDUTA.
gUpState :: Functor f => UpState f q -> GUpState f q p
gUpState f = f . fmap (below &&& (?get))

-- | This combinator turns a GDUTA with the smallest possible state
-- space into a DUTA.
upState :: GUpState f q q -> UpState f q
upState f s = let res = explicit res fst snd f s in res

-- | This combinator runs a GDUTA on a term.
runGUpState :: Functor f => GUpState f q q -> Term f -> q (Term f)
runGUpState s = runUpState (upState s)

-- | This combinator constructs the product of two GDUTA.
prodGUpState :: (p :< pq, q :< pq)
             => GUpState f p pq -> GUpState f q pq -> GUpState f (p :*: q) pq
prodGUpState sp sq t = sp t :*: sq t

-- | This type represents transition functions of deterministic
-- top-down tree transducers (DDTTs).

type DownTrans q f g = forall a. (q a, f a) -> Context g (q (Context f a),a)

-- | This function runs the given DDTT on the given tree.
runDownTrans :: (Functor f, Functor g, Functor q) => DownTrans q f g -> q (Cxt h g a) -> Cxt h f a -> Cxt h g a
runDownTrans tr q t = run (q,t) where
    run (q,Term t) = appCxt $ fmap (\(q,a) -> run (fmap appCxt q,a)) $  tr (q, t)
    run (_,Hole a) = Hole a

-- | This function runs the given DDTT on the given tree.
runDownTrans' :: (Functor f, Functor g, Functor q) => DownTrans q f g -> q (Cxt h f a)
              -> Cxt h f a -> Cxt h g (q (Cxt h f a),a)
runDownTrans' tr q t = run (q,t) where
    run (q,Term t) = appCxt $ fmap (\(q,a) -> run (fmap appCxt q,a)) $  tr (q, t)
    run (q,Hole a)      = Hole (q,a)

-- | This function composes two DDTTs. (not implemented yet)
compDownTrans :: (Functor f, Functor g, Functor h)
              => DownTrans p g h -> DownTrans q f g -> DownTrans (q :*:p) f h
compDownTrans = undefined

-- | This type represents transition functions of deterministic
-- top-down tree acceptors (DDTAs).
type DownState f q = forall a i. Ord i => (q a, f (i,a)) -> Map i (q a)

-- | This function constructs the product DDTA of the given two DDTAs.
prodDownState :: DownState f p -> DownState f q -> DownState f (p :*: q)
prodDownState sp sq (p :*: q,t) = prodMap p q (sp (p, t)) (sq (q, t))



-- | This type is needed to construct the product of two DDTAs.
data ProdState p q = LState p
                   | RState q
                   | BState p q
-- | This function constructs the pointwise product of two maps each
-- with a default value.
prodMap :: (Ord i) => p a -> q a -> Map i (p a) -> Map i (q a) -> Map i ((p :*: q) a)
prodMap p q mp mq = Map.map final $ Map.unionWith combine ps qs
    where ps = Map.map LState mp
          qs = Map.map RState mq
          combine (LState p) (RState q) = BState p q
          combine (RState q) (LState p) = BState p q
          combine _ _                   = error "unexpected merging"
          final (LState p) = p :*: q
          final (RState q) = p :*: q
          final (BState p q) = p :*: q

-- | Apply the given state mapping to the given functorial value by
-- adding the state to the corresponding index if it is in the map and
-- otherwise adding the provided default state.
appMap :: Zippable f => DownState f q -> q a -> f a -> f (q a,a)
appMap qmap q s = fmap qfun s'
    where s' = number' s
          mapping  = qmap (q,s')
          qfun (k,a) = (Map.findWithDefault q k mapping ,a)

-- -- | This function constructs a DDTT from a given stateful term
-- -- homomorphism with the state propagated by the given DDTA.
-- toDownTrans :: (Zippable f, Functor q) => DownState f q -> MHom q f g -> DownTrans q f g
-- toDownTrans st f (q, s) = fmap mkQCxt $ explicit q fst id f (appMap st q s)
--     where mkQCxt (q,a) = (fmap Hole q, a)