funcons-tools-0.1.0.0: src/Funcons/Substitution.hs
{-# LANGUAGE LambdaCase #-}
module Funcons.Substitution (
Env(..), subsAndRewrite, envInsert, emptyEnv, Levelled(..), substitute,
rewriteTermTo, stepTermTo,
) where
import Funcons.Types
import Funcons.MSOS
import Funcons.Exceptions
import Control.Monad
import Data.Monoid
import qualified Data.Map as M
-- | An environment mapping meta-variables to funcon terms.
-- This environment is used by a substitution procedure to transform
-- funcon terms from 'FTerm' representation to 'Funcons'.
type Env = M.Map MetaVar Levelled
data Levelled = ValueTerm Values
| ValuesTerm [Values]
| FunconTerm Funcons
| FunconsTerm [Funcons]
-- | The empty substitution environment.
-- Bindings are inserted by pattern-matching.
emptyEnv = M.empty
envLookup :: Env -> MetaVar -> Rewrite Levelled
envLookup env k = case M.lookup k env of
Nothing -> internal ("undefined metavar: " <> k)
Just lf -> return lf
envInsert :: MetaVar -> Levelled -> Env -> Env
envInsert = M.insert
fsLevel :: Levelled -> Rewrite [Funcons]
fsLevel = \case FunconsTerm f -> return f
FunconTerm f -> return [f]
ValuesTerm vs -> return (map FValue vs)
ValueTerm v -> return [FValue v]
fLevel k = \case FunconsTerm [f] -> return f
FunconsTerm fs
| all isVal fs -> return (FValue $ safe_tuple_val (map downcastValue fs))
| otherwise -> return (FTuple fs)
FunconTerm f -> return f
ValuesTerm vs -> return (FValue (safe_tuple_val vs))
ValueTerm v -> return (FValue v)
-- substitution
substitute :: FTerm -> Env -> Rewrite Funcons
substitute (TVar k) env = envLookup env k >>= fLevel k
substitute (TName nm) env = return $ FName nm
substitute (TApp nm term) env = do
-- if its anything but a sequence-var or a tuple, make it a singleton sequence
fs <- case term of TVar k -> envLookup env k >>= fsLevel
TTuple l -> substitute term env >>= \case
FTuple fs -> return fs
_ -> error "subsitute assert"
_ -> (:[]) <$> substitute term env
return $ FApp nm (FTuple fs)
substitute (TTuple terms) env = FTuple <$> subsFlatten terms env
-- e.g. print(V+:values+) -- standard-out![V+] -> ()
substitute (TList terms) env = FList <$> subsFlatten terms env
substitute (TSet terms) env = FSet <$> subsFlatten terms env
substitute (TMap terms) env = FMap <$> mapM (flip substitute env) terms
substitute (TFuncon f) env = return f
substitute (TSortUnion t1 t2) env = FSortUnion <$> substitute t1 env <*> substitute t2 env
substitute (TSortSeq t1 op) env = flip FSortSeq op <$> substitute t1 env
substitute (TSortComputes t1) env = FSortComputes <$> substitute t1 env
substitute (TSortComputesFrom t1 t2) env =
FSortComputesFrom <$> substitute t1 env <*> substitute t2 env
-- flatten out sequence-variables
subsFlatten :: [FTerm] -> Env -> Rewrite [Funcons]
subsFlatten terms env = concat <$> (forM terms $ \case
TVar k -> envLookup env k >>= fsLevel
term -> (:[]) <$> substitute term env)
subsAndRewrite :: FTerm -> Env -> Rewrite Values
subsAndRewrite term env = do
f <- substitute term env
rewriteFuncons f >>= \case
ValTerm v -> return v
CompTerm _ _ -> rewrite_throw (SideCondFail "premise evaluation requires step")
-- | Variant of 'rewriteTo' that applies substitution.
rewriteTermTo :: FTerm -> Env -> Rewrite Rewritten
rewriteTermTo fterm env = substitute fterm env >>= rewriteTo
-- | Variant of 'stepTo' that applies substitution.
stepTermTo :: FTerm -> Env -> MSOS Funcons
stepTermTo fterm env = do
(liftRewrite $ substitute fterm env) >>= stepTo