packages feed

transformations-0.1.0.0: examples/Regular.hs

{-# 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])) ]