module Logic.Judge.Formula.Substitution
( Substitution
, Substitutable(substitute, pattern, patternContinue)
, merge
) where
import "base" Control.Monad (void, when, sequence, ap)
import "transformers" Control.Monad.Trans.Class (lift, MonadTrans)
import "transformers" Control.Monad.Trans.State.Lazy (StateT(StateT), execStateT, get, put, evalStateT)
import qualified "containers" Data.Map as M
import Logic.Judge.Formula.Datastructure
type Substitution ext = M.Map String (Term ext)
type StateFail state result = StateT state Maybe result
class Substitutable ext term where
substitute :: Monad m
=> Substitution ext
-> term
-> m term
pattern :: (Monad m)
=> term
-> term
-> m (Substitution ext)
pattern = patternContinue M.empty
patternContinue :: (Monad m)
=> Substitution ext
-> term
-> term
-> m (Substitution ext)
patternContinue m a b = maybe (fail "pattern failed") return $ execStateT (patternM a b) m
patternM :: ()
=> term
-> term
-> StateFail (Substitution ext) ()
instance (Eq ext, Substitutable ext a) => Substitutable ext (Marked a) where
patternM (Marked m1 x1) (Marked m2 x2) = do
when (not $ all (`elem` m2) m1 && all (`elem` m1) m2) shortcircuit
patternM x1 x2
substitute subst (Marked marks x) = Marked marks <$> substitute subst x
instance (Eq ext, Substitutable ext ext) => Substitutable ext (Term ext) where
patternM (Formula f1) (Formula f2) = patternM f1 f2
patternM (Extension e1) (Extension e2) = patternM e1 e2
patternM (MarkedFormula f1) (MarkedFormula f2) = patternM f1 f2
patternM _ _ = shortcircuit
substitute subst (Formula f) = Formula <$> substitute subst f
substitute subst (Extension e) = Extension <$> substitute subst e
substitute subst (MarkedFormula f) = MarkedFormula <$> substitute subst f
instance (Eq ext, Substitutable ext ext) => Substitutable ext (Formula ext) where
patternM (Variable var) term =
var `binds` Formula term
patternM (Implication a1 a2) (Implication b1 b2) = do
a1 `patternM` b1
a2 `patternM` b2
patternM (Extend e a) (Extend e' a') = do
e `patternM` e'
a `patternM` a'
patternM (Constant a) (Constant b) =
when (a /= b) shortcircuit
patternM _ _ = shortcircuit
substitute subst term = case term of
Variable var -> case M.lookup var subst of
Just (Formula t') -> return t'
Just _ -> fail $ "gap requires different type at '" ++ var ++ "'"
_ -> fail $ "variable '" ++ var ++ "' undefined"
Constant a -> return $ Constant a
Implication a b -> Implication <$> substitute subst a <*> substitute subst b
Extend e a -> Extend <$> substitute subst e <*> substitute subst a
instance Substitutable Justification Justification where
patternM (ProofVariable var) term =
var `binds` Extension term
patternM (ProofChecker a) (ProofChecker b) =
a `patternM` b
patternM (Application a1 a2) (Application b1 b2) = do
a1 `patternM` b1
a2 `patternM` b2
patternM (Sum a1 a2) (Sum b1 b2) = do
a1 `patternM` b1
a2 `patternM` b2
patternM (ProofConstant a) (ProofConstant b) =
when (a /= b) shortcircuit
patternM _ _ = shortcircuit
substitute subst term = case term of
ProofVariable var -> case M.lookup var subst of
Just (Extension t') -> return t'
Just _ -> fail $ "gap requires different type at '" ++ var ++ "'"
_ -> fail $ "variable '" ++ var ++ "' undefined"
ProofConstant c -> return (ProofConstant c)
ProofChecker s -> ProofChecker <$> substitute subst s
Application s t -> Application <$> substitute subst s <*> substitute subst t
Sum s t -> Sum <$> substitute subst s <*> substitute subst t
shortcircuit :: MonadTrans t => t Maybe a
shortcircuit = lift Nothing
binds :: (Eq ext)
=> String
-> Term ext
-> StateFail (Substitution ext) ()
binds k v = maybe (shortcircuit) (void . put) . insert k v =<< get
insert :: (Ord k, Eq v, Monad m) => k -> v -> M.Map k v -> m (M.Map k v)
insert k v m = sequence $ M.insertWith identical k (return v) (fmap return m)
merge :: (Ord k, Eq v, Monad m) => M.Map k v -> M.Map k v -> m (M.Map k v)
merge a b = sequence $ M.unionWith identical (return <$> a) (return <$> b)
identical :: (Eq a, Monad m) => m a -> m a -> m a
identical xm ym = do
x <- xm
y <- ym
if x == y then return x
else fail "Conflicting assignment."
execute :: state -> StateFail state result -> Maybe (state, result)
execute startstate monad = flip evalStateT startstate $ do
result <- monad
state <- get
return (state, result)