tpdb-2.7.1: src/TPDB/Data/Term.hs
module TPDB.Data.Term (module T, module TPDB.Data.Term) where
import TPDB.Data.Term.Plain as T
-- import TPDB.Data.Term.Cached as T
import qualified Data.Set as S
{-# INLINEABLE vmap #-}
vmap :: (TermC v s, TermC u s) => ( v -> u ) -> Term v s -> Term u s
vmap f = tfold (Var . f) Node
-- instance Functor ( Term v ) where
-- cannot instantiate Functor since we need TermC
{-# INLINEABLE tmap #-}
tmap f = tfold Var ( \ c xs -> Node (f c) xs)
type Position = [ Int ]
positions :: TermC v c => Term v c
-> [ ( Position, Term v c ) ]
positions t = ( [], t ) : case t of
Node c args -> do ( k, arg ) <- zip [ 0 .. ] args
( p, s ) <- positions arg
return ( k : p , s )
_ -> []
-- | all positions
pos :: TermC v c => Term v c
-> [ Position ]
pos t = do
( p, s ) <- positions t
return p
-- | non-variable positions
sympos :: TermC v c => Term v c
-> [ Position ]
sympos t = do
( p, Node {} ) <- positions t
return p
-- | variable positions
varpos :: TermC v c => Term v c
-> [ Position ]
varpos t = -- if null (vars t) then [] else
do
( p, Var {} ) <- positions t
return p
-- | leaf positions (= nullary symbols)
leafpos :: TermC v c => Term v c
-> [ Position ]
leafpos t = do
( p, Node c [] ) <- positions t
return p
-- | in preorder
{-# INLINE subterms #-}
subterms :: TermC v c => Term v c
-> [ Term v c ]
subterms t = t : case t of
Node c args -> args >>= subterms
_ -> []
-- Note: following implementation relies on @subterms@
-- returning the preorder list (where the full term goes first)
strict_subterms t = tail $ subterms t
isSubtermOf :: (TermC v c, Eq v, Eq c )
=> Term v c -> Term v c -> Bool
isSubtermOf s t =
-- size s <= size t &&
(elem s $ subterms t)
isStrictSubtermOf :: (TermC v c, Eq v, Eq c )
=> Term v c -> Term v c -> Bool
isStrictSubtermOf s t =
-- size s < size t &&
(elem s $ strict_subterms t)
-- | compute new symbol at position, giving the position
pmap :: (TermC v c, TermC v d)
=>( Position -> c -> d )
-> Term v c
-> Term v d
pmap f = rpmap ( \ p c -> f ( reverse p) c )
-- | compute new symbol from *reverse* position and previous symbol
-- this is more efficient (no reverse needed)
rpmap :: (TermC v c, TermC v d)
=> ( Position -> c -> d )
-> Term v c
-> Term v d
rpmap f t = helper [] t where
helper p ( Node c args ) = Node ( f p c ) $ do
( k, arg ) <- zip [0..] args
return $ helper ( k : p ) arg
helper p ( Var v) = Var v
peek :: TermC v c
=> Term v c
-> Position
-> Term v c
peek t [] = t
peek ( Node c args ) ( k : ks ) = peek ( args !! k ) ks
peek_symbol :: TermC v c
=> Term v c
-> Position
-> c
peek_symbol t p =
case peek t p of
Node c args -> c
_ -> error "Autolib.TES.Position.peek_symbol called for non-symbol"
-- | warning: don't check arity
poke_symbol :: TermC v c
=> Term v c
-> ( Position , c )
-> Term v c
poke_symbol t ( p, c ) =
case peek t p of
Node _ args -> poke t ( p, Node c args )
_ -> error "Autolib.TES.Position.poke_symbol called for non-symbol"
poke :: TermC v c
=> Term v c
-> ( Position , Term v c )
-> Term v c
poke t ( [], s ) = s
poke (Node c args) (k : ks, s ) =
let ( pre , this : post ) = splitAt k args
in Node c ( pre ++ poke this ( ks, s ) : post )
pokes :: TermC v c
=> Term v c
-> [ ( Position, Term v c ) ]
-> Term v c
pokes = foldl poke
-- | list of function symbols (in pre-order, with duplicates)
symsl :: TermC v c => Term v c -> [ c ]
symsl t = do Node c _ <- subterms t; return c
-- | unique
lsyms :: (Ord c, TermC v c) => Term v c -> [ c ]
lsyms = S.toList . syms
isvar :: TermC v c => Term v c -> Bool
isvar ( Var _ ) = True ; isvar _ = False
-- | list of variables (each occurs once, unspecified ordering)
lvars :: (Ord v, TermC v c) => Term v c -> [ v ]
lvars = S.toList . vars
-- | list of variables (in pre-order, with duplicates)
{-# INLINE voccs #-}
voccs :: TermC v c => Term v c -> [ v ]
voccs = tfold (\ v -> [v]) (\ _ -> concat)