packages feed

transformations-0.1.1.0: examples/Regular.hs

{-# LANGUAGE FlexibleInstances  #-}
{-# LANGUAGE FlexibleContexts   #-}
{-# LANGUAGE TypeFamilies       #-}
{-# LANGUAGE TemplateHaskell    #-}
{-# LANGUAGE TypeOperators      #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# 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 Generics.Regular.Transformations.TH

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

instance HasRef Expr where
  type RefRep Expr = ExprEH
  
  toRef (Ref p)                           = RefEH p
  toRef (InR (L (K s)))                   = VarEH s
  toRef (InR (R (L (K i))))               = ConstEH i
  toRef (InR (R (R (L (I e)))))           = NegEH e
  toRef (InR (R (R (R (I e1 :*: I e2))))) = AddEH e1 e2
  
  fromRef (RefEH p)      = Ref p
  fromRef (VarEH s)      = InR (L (K s))
  fromRef (ConstEH i)    = InR (R (L (K i)))
  fromRef (NegEH e)      = InR (R (R (L (I e))))
  fromRef (AddEH e1 e2)  = InR (R (R (R (I e1 :*: I e2))))


$(deriveRefRep ''Tree (postfix "EH"))
deriving instance Show TreeEH

-- Test
instance Ex.Transform Tree
treeSwapNice :: Maybe Tree
treeSwapNice = Ex.apply (fromNiceTransformation swap) exTree1
  where swap = [([0],RefTree [1]),([1],RefTree [0])]

treeDiff :: Ex.NiceTransformation Tree
treeDiff = toNiceTransformation $ Ex.diff exTree3 exTree5

explicitInsNice :: Maybe Expr
explicitInsNice = Ex.apply (fromNiceTransformation addNeg) expr1
  where addNeg :: NiceTransformation Expr
        addNeg = [ ([1], NegEH (RefEH [1])) ]