{-# OPTIONS -XKindSignatures -XRankNTypes -XArrows -XGADTs #-} {-| Library for Typed Transformations of Typed Abstract Syntax. The library is documented in the paper: /Typed Transformations of Typed Abstract Syntax/ Bibtex entry: For more documentation see the TTTAS webpage: . For an example see examples/CSE2.hs IMPORTANT: We would like to be able to use RebinadbleSyntax to use Arrow's Syntax in this variant of TTTAS, but this extension still doesn't work well with Arrows. -} module Language.AbstractSyntax.TTTAS2 ( -- * Typed References and Environments module Language.AbstractSyntax.TTTAS.Common, -- * Transformation Library -- ** Trafo Trafo(..), TrafoE(..), -- ** Create New References newSRef, extEnv, castSRef, updateSRef, -- ** State-like operations on the Final Environment getFinalEnv, putFinalEnv, updateFinalEnv, -- ** Run a Trafo runTrafo, -- ** Arrow-style Combinators Pair(..), Arrow2(..), ArrowLoop2(..), (>>>), List(..), sequenceA, returnA ) where #if __GLASGOW_HASKELL__ >= 710 import Prelude hiding (lookup, sequenceA) #else import Prelude hiding (lookup) #endif import Language.AbstractSyntax.TTTAS.Common -- | Alternative version of 'Trafo' where the universal quantification -- over |s| is moved inside the quantification over |env2|. -- Note that the type variables |a| and |b| are now labelled with |s|, -- and hence have kind |(* -> *)|. data Trafo m t a b = Trafo (forall env1 . m env1 -> TrafoE m t env1 a b) data TrafoE m t env1 a b = forall env2 . TrafoE (m env2) (forall s . a s -> T env2 s -> Env t s env1 -> FinalEnv t s -> (b s, T env1 s, Env t s env2, FinalEnv t s) ) -- | The function 'runTrafo' takes as arguments the 'Trafo' we want to run, meta-information -- for the empty environment, and an input value. -- The result of 'runTrafo' (type 'Result') is the final environment (@Env t s s@) together -- with the resulting meta-data (@m s@), and the output value (@b s@). -- The rank-2 type for 'runTrafo2' ensures that transformation steps cannot make -- any assumptions about the type of final environment (@s@). -- It is an alternative version of 'runTrafo' which does not use -- 'unsafeCoerce'. runTrafo :: Trafo m t a b -> m () -> (forall s . a s) -> Result m t b runTrafo trafo m a = case trafo of Trafo trf -> case trf m of TrafoE m2 f -> let (rb, _, env2, fenv) = f a (T id) Empty env2 in Result m2 rb fenv -- | The Trafo2 'newSRef2' takes a typed term as input, adds it to the environment -- and yields a reference pointing to this value. -- No meta-information on the environment is recorded by 'newSRef2'; -- therefore we use the type 'Unit' for the meta-data. newSRef :: Trafo Unit t (t a) (Ref a) newSRef = Trafo (\Unit -> TrafoE Unit (\ta (T tr) env fenv -> ( tr Zero , T (tr . Suc) , Ext env ta , fenv ) ) ) -- | The function 'extEnv' returns a 'TrafoE' that extends the current environment. extEnv :: m (e,a) -> TrafoE m t e (t a ) (Ref a ) extEnv m = TrafoE m $ \ta (T tr) env fe -> (tr Zero, T (tr . Suc), Ext env ta, fe ) -- | The function 'castSRef' returns a 'TrafoE' that casts the reference -- passed as parameter (in the constructed environment) to one in the final environment. castSRef :: m e -> Ref a e -> TrafoE m t e x (Ref a) castSRef m r = TrafoE m $ (\ _ (T t) decls fe -> (t r, T t, decls, fe)) data FUpd i t a = FUpd (forall s. i -> t a s -> t a s) newtype SI i s = SI i -- | The function 'updateSRef' returns a 'TrafoE' that updates the value pointed -- by the reference passed as parameter into the current environment. updateSRef :: m e -> Ref a e -> FUpd i t a -> TrafoE m t e (SI i) (Ref a) updateSRef m r (FUpd f) = TrafoE m $ \(SI i) (T t) decls fs -> (t r, T t, updateEnv (f i) r decls, fs) newtype UpdFinalEnv t s = Upd (FinalEnv t s -> FinalEnv t s) newtype FinalEnv2 t s = Final (FinalEnv t s) -- | The function 'updateFinalEnv' returns a 'Trafo' that introduces a function -- (@(UpdFinalEnv t)@) to update the final environment. updateFinalEnv :: Trafo m t (UpdFinalEnv t) Unit updateFinalEnv = Trafo $ \m -> (TrafoE m (\(Upd u) t e fe -> (Unit, t, e, u fe))) -- | Change the final environment by the one passed in the input. putFinalEnv :: Trafo m t (FinalEnv2 t) Unit putFinalEnv = Trafo $ \m -> (TrafoE m (\(Final fe) t e _ -> (Unit, t, e, fe))) -- | Return as output the final environment. getFinalEnv :: Trafo m t Unit (FinalEnv2 t) getFinalEnv = Trafo $ \m -> (TrafoE m (\_ t e fe -> ((Final fe), t, e, fe))) {- -- | The function 'updateFinalEnv' returns a 'Trafo' that introduces a function -- (@FinalEnv t s -> FinalEnv t s@) to update the final environment. updateFinalEnv :: Trafo m t s (FinalEnv t s -> FinalEnv t s) () updateFinalEnv = proc f -> do fe <- getFinalEnv -< () putFinalEnv -< f fe -- Trafo $ \m -> (TrafoE m (\f t e fe -> ((), t, e, f fe))) -} newtype Pair a b s = P (a s, b s) class Category2 (cat :: (* -> *) -> (* -> *) -> *) where id2 :: cat a a (.:.) :: cat b c -> cat a b -> cat a c class Category2 arr => Arrow2 (arr :: (* -> *) -> (* -> *) -> *) where arr :: (forall s . a s -> b s) -> arr a b first :: arr a b -> arr (Pair a c) (Pair b c) second :: arr a b -> arr (Pair c a) (Pair c b) (***) :: arr a b -> arr a' b' -> arr (Pair a a') (Pair b b') (&&&) :: arr a b -> arr a b' -> arr a (Pair b b') class Arrow2 arr => ArrowLoop2 arr where loop :: arr (Pair a c) (Pair b c) -> arr a b instance Category2 (Trafo m t) where id2 = Trafo (\m -> TrafoE m (\a t e u -> (a, t, e, u))) (.:.) (Trafo sb) (Trafo sa) = Trafo (\m1 -> case sa m1 of TrafoE m2 f1 -> case sb m2 of TrafoE m3 f2 -> TrafoE m3 (\a t3s e1 u1 -> let (b, t1s, e2, u2) = f1 a t2s e1 u1 (c, t2s, e3, u3) = f2 b t3s e2 u2 in (c, t1s, e3, u3) )) (>>>) :: Category2 cat => cat a b -> cat b c -> cat a c f >>> g = g .:. f instance Arrow2 (Trafo m t) where arr f = Trafo (\m -> TrafoE m (\a t e u -> (f a, t, e, u)) ) first (Trafo s) = Trafo (\m1 -> case s m1 of TrafoE m2 f -> TrafoE m2 (\(P (a, c)) t2s e1 u1 -> let (b,t12,e2,u2) = f a t2s e1 u1 in (P (b, c),t12,e2,u2) ) ) second f = arr swap >>> first f >>> arr swap where swap :: Pair c a s -> Pair a c s swap ~(P (x, y)) = P (y, x) f *** g = first f >>> second g f &&& g = arr (\b -> P (b, b)) >>> (f *** g) instance ArrowLoop2 (Trafo m t) where loop (Trafo st) = Trafo (\m -> case st m of TrafoE m1 f1 -> TrafoE m1 (\a t e u -> let (P (b, x),t1,e1,u1) = f1 (P (a, x)) t e u in (b,t1,e1,u1) ) ) newtype List a s = List [a s] -- | The combinator 'sequenceA2' sequentially composes a list -- of 'Trafo2's into a 'Trafo2' that yields a 'List' of outputs. -- Its use is analogous to the combinator 'sequence' combinator -- for 'Monad's. sequenceA :: [Trafo m t a b] -> Trafo m t a (List b) sequenceA [] = arr (const (List [])) sequenceA (x:xs) = (x &&& sequenceA xs) >>> arr (\(P (a,List as)) -> List (a:as)) returnA :: Arrow2 arr => arr a a returnA = arr id