packages feed

rewriting-0.2: examples/expr/Expr.hs

{-# LANGUAGE TypeFamilies  #-}
{-# LANGUAGE TypeOperators #-}

import Generics.Regular.Rewriting


-----------------------------------------------------------------------------
-- Types and conversions
-----------------------------------------------------------------------------

infixl 7 :**:
infixl 6 :++:

data Expr = Const Int | Expr :++: Expr | Expr :**: Expr deriving Show

type instance PF Expr = K Int :+: I :*: I :+: I :*: I
instance Regular Expr where
  from (Const n)    = L (K n)
  from (e1 :++: e2) = R (L  $ (I e1) :*: (I e2))
  from (e1 :**: e2) = R (R  $ (I e1) :*: (I e2))

  to (L (K n))                     = Const n
  to (R (L ((I r1) :*: (I r2)))) = r1 :++: r2
  to (R (R ((I r1) :*: (I r2)))) = r1 :**: r2

{-
 -- with Con type constructors to specify constructor names.
instance Regular Expr where
  type PF Expr = Con (K Int) :+: Con (I :*: I) :+: Con (I :*: I)

  from (Const n)    = L (Con "Const" (K n))
  from (e1 :++: e2) = R (L (Con "(:++:)" $ (I e1) :*: (I e2)))
  from (e1 :**: e2) = R (R (Con "(:**:)" $ (I e1) :*: (I e2)))

  to (L (Con _ (K n)))                     = Const n
  to (R (L (Con _ ((I r1) :*: (I r2))))) = r1 :++: r2
  to (R (R (Con _ ((I r1) :*: (I r2))))) = r1 :**: r2
-}

instance Rewrite Expr

-----------------------------------------------------------------------------
-- Example rules
-----------------------------------------------------------------------------

rule1 :: Rule Expr
rule1 = 
  rule $ \x -> x :++: Const 0 :~>
               x

rule2 :: Rule Expr
rule2 = 
  rule $ \x -> x :++: x :~> 
               Const 2 :**: x

rule3 :: Rule Expr
rule3 =
  rule $ \x y -> x :++: y :~> 
                 y :++: x

rule4 :: Rule Expr
rule4 =  
  rule $ \x y -> Const 2 :**: (x :++: y) :~>
                 (Const 2 :**: x) :++: (Const 2 :**: y)

rule5 :: Rule Expr
rule5 = 
  rule $ \x y z -> x :**: (y :++: z) :~>  
                   (x :**: y) :++: (x :**: z) 

rule6 :: Rule Expr
rule6 = 
  rule $ Const 1 :++: Const 1 :~>
         Const 2


-----------------------------------------------------------------------------
-- Tests
-----------------------------------------------------------------------------

test1 :: Maybe Expr
test1 = rewriteM rule1 (Const 2 :++: Const 0)

test2 :: Maybe Expr
test2 = rewriteM rule1 (Const 2 :++: Const 3)

test3 :: Maybe Expr
test3 = rewriteM rule2 (Const 4 :++: Const 3)

test4 :: Maybe Expr
test4 = rewriteM rule2 (Const 4 :++: Const 4)

test5 :: Maybe Expr
test5 = one (rewriteM rule1) ((Const 4 :++: Const 0) :**: Const 2)

-- This does not work because the optimisation target is not
-- an immediate child.
test6 :: Maybe Expr
test6 = one (rewriteM rule1) (((Const 4 :++: Const 0) :**: Const 2) :++: Const 7)

-- This works well, because once applies the rule to the optimisation
-- target exactly once.
test7 :: Maybe Expr
test7 = once (rewriteM rule1) (((Const 4 :++: Const 0) :**: Const 2) :++: Const 7)

test8 :: Maybe Expr
test8 = rewriteM rule3 ((Const 1) :++: (Const 2))

test9 :: Maybe Expr
test9 = rewriteM rule4 ((Const 2) :**: ((Const 3) :++: (Const 4)))

test10 :: Maybe Expr
test10 = rewriteM rule5 ((Const 1) :**: ((Const 2) :++: (Const 3)))

test11 :: Maybe Expr
test11 = rewriteM rule6 (Const 1 :++: Const 1)

allTests :: [Maybe Expr]
allTests = [ test1
           , test2
           , test3
           , test4
           , test5
           , test6
           , test7
           , test8
           , test9
           , test10
           , test11
           ]


-----------------------------------------------------------------------------
-- Running all the tests
-----------------------------------------------------------------------------

-- This main function is defined to solve a bug in GHC
main :: IO ()
main = do let resultsPP         = zipWith resultPP [1..] allTests
              resultPP n result = "test" ++ show n ++ ": " ++ show result
          putStr (unlines resultsPP)