packages feed

pointless-rewrite-0.0.3: src/Transform/Rules/PF/Combinators.hs

-----------------------------------------------------------------------------
-- |
-- Module      :  Transform.Rules.PF.Combinators
-- Copyright   :  (c) 2010 University of Minho
-- License     :  BSD3
--
-- Maintainer  :  hpacheco@di.uminho.pt
-- Stability   :  experimental
-- Portability :  non-portable
--
-- Pointless Rewrite:
-- automatic transformation system for point-free programs
-- 
-- Combinators for the rewriting of point-free functions.
--
-----------------------------------------------------------------------------

module Transform.Rules.PF.Combinators where

import Data.Type
import Data.Pf
import Data.Lens
import Data.Equal
import Transform.Rewriting

import Prelude hiding (Functor(..))
import Control.Monad hiding (Functor(..))

-- ** Combinators

comp :: Rule -> Rule
comp r (Fun d a) (COMP b f (COMP c g h)) = do
    fg <- r (Fun c a) (COMP b f g)
    return $ COMP c fg h
comp r (Fun d a) (COMP c (COMP b f g) h) = do
    gh <- r (Fun d b) (COMP c g h)
    return $ COMP b f gh
comp r t f = r t f

comp1 :: Rule -> Rule
comp1 r (Fun a c) (COMP b f g) = do
    f' <- r (Fun b c) f
    return $ COMP b f' g
comp1 _ _ _ = mzero

comp2 :: Rule -> Rule
comp2 r (Fun a c) (COMP b f g) = do
    g' <- r (Fun a b) g
    return $ COMP b f g'
comp2 _ _ _ = mzero

prod1 :: Rule -> Rule
prod1 r (Fun (Prod a b) (Prod c d)) (f `PROD` g) = do
    f' <- r (Fun a c) f
    return $ f' `PROD` g
prod1 _ _ _ = mzero

prod2 :: Rule -> Rule
prod2 r (Fun (Prod a b) (Prod c d)) (f `PROD` g) = do
    g' <- r (Fun b d) g
    return $ f `PROD` g'
prod2 _ _ _ = mzero

sum1 :: Rule -> Rule
sum1 r (Fun (Either a b) (Either c d)) (f `SUM` g) = do
    f' <- r (Fun a c) f
    return $ f' `SUM` g
sum1 _ _ _ = mzero

sum2 :: Rule -> Rule
sum2 r (Fun (Either a b) (Either c d)) (f `SUM` g) = do
    g' <- r (Fun b d) g
    return $ f `SUM` g'
sum2 _ _ _ = mzero

precomp :: Rule -> Rule -> Rule
precomp r1 r2 = comp $ r2 ||| (comp1 r1 >>> comp_assocr >>> comp2 r2)

postcomp :: Rule -> Rule -> Rule
postcomp r1 r2 = comp $ r2 ||| (comp2 r1 >>> comp_assocl >>> comp1 r2)

rightmost :: Rule
rightmost (Fun a c) (COMP b f g) = do
    g' <- rightmost' (Fun a b) g
    try comp_assocl (Fun a c) $ COMP b f g'
rightmost (Fun a c) f =
    return $ COMP c ID f
rightmost _ _ = mzero
rightmost' :: Rule
rightmost' (Fun a c) (COMP b f g) = do
    g' <- rightmost' (Fun a b) g
    try comp_assocl (Fun a c) $ COMP b f g'
rightmost' (Fun a c) f = return f
rightmost' _ _ = mzero

leftmost :: Rule
leftmost (Fun a c) (COMP b f g) = do
    f' <- leftmost' (Fun b c) f
    try comp_assocr (Fun a c) $ COMP b f' g
leftmost (Fun a c) f =
    return $ COMP a f ID
leftmost _ _ = mzero
leftmost' :: Rule
leftmost' (Fun a c) (COMP b f g) = do
    f' <- leftmost' (Fun b c) f
    try comp_assocr (Fun a c) $ COMP b f' g
leftmost' (Fun a c) f = return f
leftmost' _ _ = mzero

leftmost_sum :: Rule
leftmost_sum (Fun (Either a b) (Either c d)) (SUM ID ID) = mzero
leftmost_sum (Fun (Either a b) (Either c d)) (SUM ID g) = do
    COMP y g' g'' <- leftmost' (Fun b d) g
    return $ COMP (Either a y) (ID -|-= g') (ID -|-= g'')
leftmost_sum (Fun (Either a b) (Either c d)) (SUM f ID) = do
    COMP x f' f'' <- leftmost' (Fun a c) f
    return $ COMP (Either x b) (f' -|-= ID) (f'' -|-= ID)
leftmost_sum (Fun (Either a b) (Either c d)) (SUM f g) = do
    COMP x f' f'' <- leftmost' (Fun a c) f
    COMP y g' g'' <- leftmost' (Fun b d) g
    return $ COMP (Either x y) (f' -|-= g') (f'' -|-= g'')
leftmost_sum _ _ = mzero

rightmost_sum :: Rule
rightmost_sum (Fun (Either a b) (Either c d)) (SUM ID ID) = mzero
rightmost_sum (Fun (Either a b) (Either c d)) (SUM ID g) = do
    COMP y g' g'' <- rightmost' (Fun b d) g
    return $ COMP (Either a y) (ID -|-= g') (ID -|-= g'')
rightmost_sum (Fun (Either a b) (Either c d)) (SUM f ID) = do
    COMP x f' f'' <- rightmost' (Fun a c) f
    return $ COMP (Either x b) (f' -|-= ID) (f'' -|-= ID)
rightmost_sum (Fun (Either a b) (Either c d)) (SUM f g) = do
    COMP x f' f'' <- rightmost' (Fun a c) f
    COMP y g' g'' <- rightmost' (Fun b d) g
    return $ COMP (Either x y) (f' -|-= g') (f'' -|-= g'')
rightmost_sum _ _ = mzero

leftmost_prod :: Rule
leftmost_prod (Fun (Prod a b) (Prod c d)) (PROD ID ID) = mzero
leftmost_prod (Fun (Prod a b) (Prod c d)) (PROD ID g) = do
    COMP y g' g'' <- leftmost' (Fun b d) g
    return $ COMP (Prod a y) (ID ><= g') (ID ><= g'')
leftmost_prod (Fun (Prod a b) (Prod c d)) (PROD f ID) = do
    COMP x f' f'' <- leftmost' (Fun a c) f
    return $ COMP (Prod x b) (f' ><= ID) (f'' ><= ID)
leftmost_prod (Fun (Prod a b) (Prod c d)) (PROD f g) = do
    COMP x f' f'' <- leftmost' (Fun a c) f
    COMP y g' g'' <- leftmost' (Fun b d) g
    return $ COMP (Prod x y) (f' ><= g') (f'' ><= g'')
leftmost_prod _ _ = mzero

rightmost_prod :: Rule
rightmost_prod (Fun (Prod a b) (Prod c d)) (PROD ID ID) = mzero
rightmost_prod t@(Fun (Prod a b) (Prod c d)) v@(PROD ID g) = do
    COMP y g' g'' <- rightmost' (Fun b d) g
    return $ COMP (Prod a y) (ID ><= g') (ID ><= g'')
rightmost_prod t@(Fun (Prod a b) (Prod c d)) v@(PROD f ID) = do
    COMP x f' f'' <- rightmost' (Fun a c) f
    return $ COMP (Prod x b) (f' ><= ID) (f'' ><= ID)
rightmost_prod t@(Fun (Prod a b) (Prod c d)) v@(PROD f g) = do
    COMP x f' f'' <- rightmost' (Fun a c) f
    COMP y g' g'' <- rightmost' (Fun b d) g
    return $ COMP (Prod x y) (f' ><= g') (f'' ><= g'')
rightmost_prod _ _ = mzero


-- ** Identity and Composition

nat_id = comp nat_id'
nat_id' :: Rule
nat_id' _ (COMP _ ID f) = return f
nat_id' _ (COMP _ f ID) = return f
nat_id' _ _ = mzero

comp_assocr :: Rule
comp_assocr _ (COMP a (COMP b f g) h) =
    return $ (COMP b f (COMP a g h))
comp_assocr _ _ = mzero

comp_assocl :: Rule
comp_assocl _ (COMP a f (COMP b g h)) =
    return $ (COMP b (COMP a f g) h)
comp_assocl _ _ = mzero

-- ** Bangs

bang_reflex :: Rule
bang_reflex (Fun One One) BANG =
    success "bang-Reflex" ID
bang_reflex _ _ = mzero

bang_fusion = comp bang_fusion'
bang_fusion' :: Rule
bang_fusion' t@(Fun a One) v@(COMP b BANG f) = do
    success "bang-Fusion" BANG
bang_fusion' _ _ = mzero

bang_uniq :: Rule
bang_uniq (Fun _ _) ID = mzero
bang_uniq (Fun _ _) BANG = mzero
bang_uniq (Fun a One) l1 =
    success "bang-Uniq" BANG
bang_uniq _ _ = mzero
    
-- ** Lens laws

create_def :: Rule
create_def t@(Fun a c) (CREATE l) = do
    success "create-Def" $ createof (Lns c a) l
create_def _ _ = mzero

get_def :: Rule
get_def (Fun c a) (GET l) = do
    success "get-Def" $ getof (Lns c a) l
get_def _ _ = mzero

put_def :: Rule
put_def (Fun (Prod a c) _) (PUT l) = do
    success "put-Def" $ putof (Lns c a) l
put_def _ _ = mzero

-- * Lens laws

create_get = comp create_get'
create_get' :: Rule
create_get' (Fun a a') (COMP c (GET f) (CREATE f')) = do
    Eq <- teq a a'
    guard $ geq (Pf $ Lns c a) f f'
    success "Create-Get" ID
create_get' _ _ = mzero

put_get = comp put_get'
put_get' :: Rule
put_get' (Fun (Prod a c) a') (COMP _ (GET f) (PUT f')) = do
    Eq <- teq a a'
    guard $ geq (Pf $ Lns c a) f f'
    success "Put-Get" FST
put_get' _ _ = mzero

get_put = comp get_put'
get_put' :: Rule
get_put' (Fun c c') (COMP (Prod a _) (PUT f) (GET f' `SPLIT` ID)) = do
    Eq <- teq c c'
    guard $ geq (Pf $ Lns c a) f f'
    success "Get-Put" ID
get_put' _ _ = mzero

create_put = comp create_put'
create_put' :: Rule
create_put' (Fun a c) (COMP (Prod _ c') (PUT f) (ID `SPLIT` CREATE f')) = do
    Eq <- teq c c'
    guard $ geq (Pf $ Lns c a) f f'
    success "Create-Put" $ CREATE f
create_put' _ _ = mzero

put_twice = comp put_twice'
put_twice' :: Rule
put_twice' (Fun (Prod a c) c') (COMP _ (PUT l) (FST `SPLIT` PUT l')) = do
    Eq <- teq c c'
    guard $ geq (Pf $ Lns c a) l l'
    success "Put-Twice" $ PUT l
put_twice' (Fun a c) (COMP (Prod b _) (PUT l) (f `SPLIT` (COMP (Prod b' c') (PUT l') (f' `SPLIT` g)))) = do
    Eq <- teq b b'
    Eq <- teq c c'
    guard $ geq (Pf $ Fun a b) f f'
    guard $ geq (Pf $ Lns c b) l l'
    success "Put-Twice" $ COMP (Prod b c) (PUT l) $ f /\= g 
put_twice' _ _ = mzero

-- ** Backtracking sums and products

prod_wunfusion :: Rule
prod_wunfusion t@(Fun a _) (COMP x f g `SPLIT` COMP y h g') = do
    Eq <- teq x y
    guard $ geq (Pf $ Fun a x) g g'
    success "prod-Unfusion" $ COMP x (f `SPLIT` h) g
prod_wunfusion _ _ = mzero

prod_unfusion :: Rule
prod_unfusion _ (ID `SPLIT` ID) = mzero
prod_unfusion t@(Fun a (Prod b c)) w@(f `SPLIT` g) = do
    COMP x f' h  <- (sum_unfusion ||| rightmost) (Fun a b) f
    COMP y g' h' <- (sum_unfusion ||| rightmost) (Fun a c) g
    Eq <- teq x y
    guard $ geq (Pf $ Fun a x) h h'
    res <- try (comp1 prod_unfusion >>> comp_assocr) t (COMP x (f' /\= g') h)
    success "prod-UnFusion" res
prod_unfusion _ _ = mzero

sum_unfusion :: Rule
sum_unfusion _ (ID `EITHER` ID) = mzero
sum_unfusion t@(Fun (Either a b) c) w@(f `EITHER` g) = do
    COMP x h  f' <- (prod_unfusion ||| leftmost) (Fun a c) f
    COMP y h' g' <- (prod_unfusion ||| leftmost) (Fun b c) g
    Eq <- teq x y
    guard $ geq (Pf $ Fun x c) h h'
    res <- try (comp2 sum_unfusion >>> comp_assocl) t (COMP x h (f' \/= g'))
    success "sum-UnFusion" res
sum_unfusion _ _ = mzero    

-- ** Tops and Bottoms

top_fusion = comp top_fusion'
top_fusion' :: Rule
top_fusion' (Fun _ _) (COMP _ TOP f) =
    success "top-Fusion" TOP
top_fusion' (Fun _ _) (COMP _ f TOP) =
    success "top-Fusion" TOP
top_fusion' _ _ = mzero

dyn_cancel, dyn_cancel' :: Rule
dyn_cancel = comp dyn_cancel'
dyn_cancel' _ (COMP _ (UNDYN a) (MKDYN b)) = do
    Eq <- teq a b
    success "dyn-Cancel" ID
dyn_cancel' _ _ = mzero

cast_cancel, cast_cancel' :: Rule
cast_cancel = comp cast_cancel'
cast_cancel' _ (COMP _ (CAST a) (MKDYN b)) = do
	cast_cancel' (Fun b a) (CAST a)
cast_cancel' (Fun b@(Data s f) _) (CAST a) | isBasic a = do
	Eq <- teq (rep f b) a
	success "cast-Cancel" OUT
cast_cancel' (Fun b@(NewData s f) _) (CAST a) | isBasic a = do
	Eq <- teq (rep f b) a
	success "cast-Cancel" OUT
cast_cancel' (Fun b _) (CAST a) = do
	Eq <- teq a b
	success "cast-Cancel" ID
cast_cancel' _ _ = mzero

primitives :: Rule
primitives = top comp_assocr ||| top nat_id ||| top dyn_cancel ||| top cast_cancel ||| top top_fusion

bangs :: Rule
bangs = top bang_reflex ||| top bang_fusion ||| top bang_uniq

-- ** Relating sums with products

abides = abides'
abides' :: Rule
abides' (Fun _ _) ((f `SPLIT` g) `EITHER` (h `SPLIT` i)) =
    success "abides" $ (f \/= h) /\= (g \/= i)
abides' _ _ = mzero

unabides = unabides'
unabides' :: Rule
unabides' (Fun _ _) ((f `EITHER` h) `SPLIT` (g `EITHER` i)) =
    success "unabides" $ (f /\= g) \/= (h /\= i)
unabides' _ _ = mzero