{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE EmptyDataDecls #-}
module Regular where
import Datatypes
import Generics.Regular hiding (right)
import Generics.Regular.Transformations.Explicit as Ex
import Generics.Regular.Transformations.RewriteRules as RR
import Generics.Regular.Zipper
import Generics.Regular.Transformations.ZipperState
import Control.Monad ( (>=>) )
import Generics.Regular.Rewriting hiding (left, right)
import Data.Maybe (fromJust)
--------------------------------------------------------------------------------
-- Regular representations for the example datatypes
--------------------------------------------------------------------------------
--Trees
$(deriveAll ''Tree "PFTree")
type instance PF Tree = PFTree
-- Lists
$(deriveAll ''List "PFL")
type instance PF (List a) = PFL a
-- Something more exotic
$(deriveAll ''X "PFX")
type instance PF X = PFX
-- Example for paper (do manual instance to avoid C's)
type instance PF Expr = K String :+: K Integer :+: I :+: I :*: I
instance Regular Expr where
from (Var s) = L (K s)
from (Const i) = R (L (K i))
from (Neg e) = R (R (L (I e)))
from (Add e1 e2) = R (R (R (I e1 :*: I e2)))
to (L (K s)) = Var s
to (R (L (K i))) = Const i
to (R (R (L (I e)))) = Neg e
to (R (R (R (I e1 :*: I e2)))) = Add e1 e2
--------------------------------------------------------------------------------
-- Examples for the paper
--------------------------------------------------------------------------------
-- Some example values
expr1 :: Expr
expr1 = Add (Const 1) (Var "a")
expr2 :: Expr
expr2 = Add (Const 1) (Neg (Var "a"))
expr3 :: Expr
expr3 = Add (Var "a") (Const 1)
instance RR.Transform Expr
instance Ex.Transform Expr
instance Show (Fix (WithRef Expr)) where
show (In (Ref p)) = "Ref " ++ show p
-- Insertion (expr1 => expr2)
rewriteRulesIns :: Maybe Expr
rewriteRulesIns = RR.apply [(down >=> right, rule1)] expr1
where rule1 :: Rule Expr
rule1 = rule $ \x -> x :~> Neg x
zipperStateIns :: Maybe Expr
zipperStateIns = navigate expr1 $ do
downMonad >> rightMonad
updateMonad Neg
explicitIns :: Maybe Expr
explicitIns = Ex.apply addNeg expr1
where addNeg :: Ex.Transformation Expr
addNeg = [ ([1], In . InR . R . R . L . I . In $ Ref [1]) ]
-- Deletion (expr2 => expr1)
rewriteRulesDel :: Maybe Expr
rewriteRulesDel = RR.apply [(down >=> right, rule2)] expr2
where rule2 :: Rule Expr
rule2 = rule $ \x -> Neg x :~> x
zipperStateDel :: Maybe Expr
zipperStateDel = navigate expr2 $ do
r <- downMonad >> rightMonad >> downMonad
upMonad
updateMonad (const r)
explicitDel :: Maybe Expr
explicitDel = Ex.apply delNeg expr2
where delNeg :: Ex.Transformation Expr
delNeg = [ ([1], In (Ref [1,0])) ]
-- Swapping (expr1 => expr3)
rewriteRulesSwap :: Maybe Expr
rewriteRulesSwap = RR.apply [(return, rule3)] expr1
where rule3 :: Rule Expr
rule3 = rule $ \l r -> Add l r :~> Add r l
zipperStateSwap :: Maybe Expr
zipperStateSwap = navigate expr1 $ do
l <- downMonad
r <- rightMonad
updateMonad (const l)
leftMonad
updateMonad (const r)
explicitSwap :: Maybe Expr
explicitSwap = Ex.apply swap' expr1
where swap' :: Ex.Transformation Expr
swap' = [ ([0], In $ Ref [1])
, ([1], In $ Ref [0])]
-- Rotation
rotate1 = Add (Var "a") (Add (Var "b") (Var "c"))
rotate2 = Add (Add (Var "a") (Var "b")) (Var "c")
rotate = diff rotate1 rotate2
--------------------------------------------------------------------------------
-- Other RewriteRules examples
--------------------------------------------------------------------------------
instance RR.Transform Tree
instance RR.Transform X
-- Test swapping two subtrees. Note the nice syntax!
swap :: Rule Tree
swap = rule $ \t1 t2 -> Bin t1 t2 :~> Bin t2 t1
t1 = RR.apply [(return , swap)] exTree4
t2 = RR.apply [(down , swap)] exTree4
t3 = RR.apply [(down >=> right, swap)] exTree4
t4 = RR.apply [(down >=> right, swap), (return, swap)] exTree4 -- == id
-- A tricky example
ruleSwapC, ruleAddB :: Rule X
ruleSwapC = rule $ \x y -> XC x y :~> XC y x
ruleAddB = rule $ \x -> XA x :~> XA (XB x)
t6 = RR.apply [(down >=> down >=> down, ruleSwapC)] exX1
t7 = RR.apply [(down >=> down, ruleAddB)] (fromJust t6)
t8 = RR.apply [(return, ruleAddB)] (fromJust t7)
t9 = t8 == Just exX2 -- True
--------------------------------------------------------------------------------
-- Other ZipperState examples
--------------------------------------------------------------------------------
-- An example using a zipper with state
t5 = navigate exTree4 $
do downMonad >> downMonad
saveMonad
upMonad >> rightMonad >> downMonad >> rightMonad
saveMonad
x1 <- loadMonad
updateMonad (const x1)
upMonad >> leftMonad >> downMonad
x2 <- loadMonad
updateMonad (const x2)
--------------------------------------------------------------------------------
-- A nicer interface for Expr, could be generated using Template Haskell
--------------------------------------------------------------------------------
data ExprEH
= VarEH String
| ConstEH Integer
| NegEH ExprEH
| AddEH ExprEH ExprEH
| RefEH Path
deriving Show
class HasRef a where
type RefRep a
toRef :: Fix (WithRef a) -> RefRep a
fromRef :: RefRep a -> Fix (WithRef a)
instance HasRef Expr where
type RefRep Expr = ExprEH
toRef (In (Ref p)) = RefEH p
toRef (In (InR (L (K s)))) = VarEH s
toRef (In (InR (R (L (K i))))) = ConstEH i
toRef (In (InR (R (R (L (I e)))))) = NegEH (toRef e)
toRef (In (InR (R (R (R (I e1 :*: I e2)))))) = AddEH (toRef e1) (toRef e2)
fromRef (RefEH p) = In (Ref p)
fromRef (VarEH s) = In (InR (L (K s)))
fromRef (ConstEH i) = In (InR (R (L (K i))))
fromRef (NegEH e) = In (InR (R (R (L (I (fromRef e))))))
fromRef (AddEH e1 e2) = In (InR (R (R (R (I (fromRef e1) :*: I (fromRef e2))))))
-- Provide the interface
type NiceTransformation a = [ (Path, RefRep a) ]
toNiceTransformation :: HasRef a => Ex.Transformation a -> NiceTransformation a
toNiceTransformation = map (\(p,e) -> (p, toRef e))
fromNiceTransformation :: HasRef a => NiceTransformation a -> Ex.Transformation a
fromNiceTransformation = map (\(p,e) -> (p,fromRef e))
explicitInsNice :: Maybe Expr
explicitInsNice = Ex.apply (fromNiceTransformation addNeg) expr1
where addNeg :: NiceTransformation Expr
addNeg = [ ([1], NegEH (RefEH [1])) ]