module Test.StateMachine.Internal.AlphaEquality
( alphaEq
, alphaEqFork
) where
import Control.Monad.State
(State, get, modify, evalState, runState)
import Data.Map
(Map)
import qualified Data.Map as M
import Test.StateMachine.Types
import Test.StateMachine.Internal.Types
alphaEq
:: (HFunctor act, Eq (Program act))
=> Program act -> Program act
-> Bool
alphaEq acts1 acts2 = canonical acts1 == canonical acts2
canonical :: HFunctor act => Program act -> Program act
canonical = Program . fst . flip runState M.empty . canonical' . unProgram
canonical' :: HFunctor act => [Internal act] -> State (Map Var Var) [Internal act]
canonical' [] = return []
canonical' (Internal act (Symbolic var) : acts) = do
env <- get
let act' = hfmap (\(Symbolic v) -> Symbolic (env M.! v)) act
var' = Var (M.size env)
sym' = Symbolic var'
modify (M.insert var var')
ih <- canonical' acts
return (Internal act' sym' : ih)
alphaEqFork
:: (HFunctor act, Eq (Program act))
=> Fork (Program act) -> Fork (Program act)
-> Bool
alphaEqFork f1 f2 = canonicalFork f1 == canonicalFork f2
canonicalFork :: HFunctor act => Fork (Program act) -> Fork (Program act)
canonicalFork (Fork l p r) = Fork (Program l') (Program p') (Program r')
where
(p', m) = runState (canonical' (unProgram p)) M.empty
l' = evalState (canonical' (unProgram l)) m
r' = evalState (canonical' (unProgram r)) m