dedukti-1.0.0: Dedukti/Core.hs
-- |
-- Copyright : © 2009 CNRS - École Polytechnique - INRIA
-- License : GPL
module Dedukti.Core
( -- * Terms
Expr(..), Binding(..)
-- * Rules
, Rule(..), Env, TyRule(..), RuleSet(..)
-- * Type Synonyms
, Module
-- * Type functions
, Id, A
-- * Convenience functions
, (.->)
, bind_name, bind_type
, isAbstraction, isApplication, isVariable, isAtomic, isApplicative
-- * Environments
, emptyEnv, env_bindings, env_domain, env_codomain, (&), (!), isin
-- * Annotations
, Unannot, nann, (%%), (%%%), (<%%>), (<%%%>)
-- * Smart constructors
, abstract, apply, unapply
-- * Transformations
, Transform(..), transform, descend
-- * Query
, everyone
) where
import Control.Applicative
import Control.Monad.Identity
import Control.Monad.State
import qualified Data.Map as Map
data Expr id a = Lam (Binding id a) (Expr id a) a
| Pi (Binding id a) (Expr id a) a
| App (Expr id a) (Expr id a) a
| Var id a
| Type
| Kind
deriving (Eq, Ord, Show)
infix 2 :::
-- | A type decorating a variable, or a type on its own.
data Binding id a = id ::: Expr id a
| Hole (Expr id a)
deriving (Eq, Ord, Show)
-- | A rewrite rule.
data Rule id a = Expr id a :--> Expr id a
deriving (Eq, Ord, Show)
infix 9 :-->
-- | An environment is and *ordered* list of bindings, since types can depend
-- on items defined earlier in environment. We opt for a hybrid
-- representation, for both fast membership tests and conservation of order.
data Env id a = Env [Binding id a] (Map.Map id (Expr id a))
deriving (Eq, Ord, Show)
-- | A rewrite rule paired with a typing environment.
data TyRule id a = Env id a :@ Rule id a
deriving (Eq, Ord, Show)
infix 8 :@
-- | A set of rewrite rules sharing a same head constant.
-- Invariant:
--
-- > all ((== rs_name ruleset) . headConstant) (rs_rules ruleset)
data RuleSet id a = RS { rs_name :: id
, rs_type :: Expr id a
, rs_rules :: [TyRule id a] }
deriving (Eq, Ord, Show)
type Module id a = ([Binding id a], [TyRule id a])
type family Id t
type family A t
type instance Id (Module id a) = id
type instance Id (Binding id a) = id
type instance Id (Rule id a) = id
type instance Id (TyRule id a) = id
type instance Id (RuleSet id a) = id
type instance Id (Expr id a) = id
type instance A (Module id a) = a
type instance A (Binding id a) = a
type instance A (Rule id a) = a
type instance A (TyRule id a) = a
type instance A (RuleSet id a) = a
type instance A (Expr id a) = a
x .-> y = Pi (Hole x) y
infixr .->
bind_type (x ::: ty) = ty
bind_type (Hole ty) = ty
bind_name (x ::: _) = x
bind_name (Hole _) = error "Binding has no name."
isAbstraction (Lam _ _ _) = True
isAbstraction (Pi _ _ _) = True
isAbstraction _ = False
isApplication (App _ _ _) = True
isApplication _ = False
isVariable (Var _ _) = True
isVariable _ = False
isAtomic (Var _ _) = True
isAtomic Type = True
isAtomic Kind = True
isAtomic _ = False
isApplicative x = isAtomic x || isApplication x
env_bindings (Env bs _) = bs
env_domain (Env bs map) = Map.keys map
env_codomain (Env bs map) = Map.elems map
infix 1 &
emptyEnv = Env [] Map.empty
-- | Extend an environment with a new binding.
(&) :: Ord id => Binding id a -> Env id a -> Env id a
x ::: ty & Env bs map = Env ((x ::: ty) : bs) (Map.insert x ty map)
(!) :: Ord id => Env id a -> id -> Expr id a
Env _ map ! x = map Map.! x
isin :: Ord id => id -> Env id a -> Bool
isin x (Env _ map) = Map.member x map
fromBindings :: Ord id => [Binding id a] -> Env id a
fromBindings = foldr (&) (Env [] Map.empty)
-- | Phantom type used to express no annotation.
data Unannot = Unannot deriving (Eq, Ord, Show)
-- | Unannot should stay abstract. |nann| constructs a value of type |Unannot|.
nann = Unannot
-- | Annotation operator.
(%%) :: (a -> Expr id a) -> a -> Expr id a
(%%) = ($)
-- | Apply annotations to an annotation expecting context.
(%%%) :: ([a] -> Expr id a) -> [a] -> Expr id a
(%%%) = ($)
-- | Applicative annotation operator.
(<%%>) :: Applicative f => f (a -> Expr id a) -> a -> f (Expr id a)
x <%%> a = x <*> pure a
-- | Applicative multi-annotation operator.
(<%%%>) :: Applicative f => f ([a] -> Expr id a) -> [a] -> f (Expr id a)
x <%%%> a = x <*> pure a
infixl 1 %%
infixl 1 %%%
infixl 1 <%%>
infixl 1 <%%%>
-- | Invariant: in abstract xs t annots, length annots == length xs.
abstract :: [Binding id a] -> Expr id a -> [a] -> Expr id a
abstract [] t _ = t
abstract (x:xs) t (a:annots) = Lam x (abstract xs t annots) %% a
abstract _ _ _ = error "Fewer annotations than number of variables."
-- | Invariant: in apply ts annots, length annots == length ts - 1.
apply :: Expr id a -> [Expr id a] -> [a] -> Expr id a
apply t [] _ = t
apply t (x:xs) (a:annots) = apply (App t x %% a) xs annots
apply _ _ _= error "Fewer annotations than number of applications."
-- | Turn nested applications into a list.
unapply :: Expr id a -> [Expr id a]
unapply = reverse . aux where
aux (App t1 t2 _) = t2 : aux t1
aux t = [t]
class Ord (Id t) => Transform t where
-- | Effectful bottom-up transformation on terms.
transformM :: (Monad m, Ord (Id t)) => (Expr (Id t) (A t) -> m (Expr (Id t) (A t))) -> t -> m t
-- | Helper function for top-down transformations.
descendM :: (Monad m, Ord (Id t)) => (Expr (Id t) (A t) -> m (Expr (Id t) (A t))) -> t -> m t
instance Ord id => Transform (Module id a) where
transformM f (decls, rules) =
return (,) `ap` mapM (transformM f) decls `ap` mapM (transformM f) rules
descendM f (decls, rules) =
return (,) `ap` mapM (descendM f) decls `ap` mapM (descendM f) rules
instance Ord id => Transform (Binding id a) where
transformM f (x ::: ty) = return (x :::) `ap` transformM f ty
transformM f (Hole ty) = return Hole `ap` transformM f ty
descendM f (x ::: ty) = return (x :::) `ap` f ty
descendM f (Hole ty) = return Hole `ap` f ty
instance Ord id => Transform (TyRule id a) where
transformM f (env :@ rule) =
return (:@) `ap` (return fromBindings `ap` mapM (transformM f) (env_bindings env)) `ap`
transformM f rule
descendM f (env :@ rule) =
return (:@) `ap` (return fromBindings `ap` mapM (descendM f) (env_bindings env)) `ap`
descendM f rule
instance Ord id => Transform (Rule id a) where
transformM f (lhs :--> rhs) =
return (:-->) `ap` transformM f lhs `ap` transformM f rhs
descendM f (lhs :--> rhs) = return (:-->) `ap` f lhs `ap` f rhs
instance Ord id => Transform (RuleSet id a) where
transformM f RS{..} =
return RS `ap` return rs_name `ap` transformM f rs_type `ap` mapM (transformM f) rs_rules
descendM f RS{..} =
return RS `ap` return rs_name `ap` descendM f rs_type `ap` mapM (descendM f) rs_rules
instance Ord id => Transform (Expr id a) where
transformM f (Lam (x ::: ty) t a) = do
ty' <- transformM f ty
t' <- transformM f t
f $ Lam (x ::: ty') t' a
transformM f (Lam (Hole ty) t a) = do
ty' <- transformM f ty
t' <- transformM f t
f $ Lam (Hole ty') t' a
transformM f (Pi (x ::: ty) t a) = do
ty' <- transformM f ty
t' <- transformM f t
f $ Pi (x ::: ty') t' a
transformM f (Pi (Hole ty) t a) = do
ty' <- transformM f ty
t' <- transformM f t
f $ Pi (Hole ty') t' a
transformM f (App t1 t2 a) = do
f =<< return App `ap` transformM f t1 `ap` transformM f t2 `ap` return a
transformM f t = f t
descendM f (Lam (x ::: ty) t a) = do
ty' <- f ty
t' <- f t
return $ Lam (x ::: ty') t' a
descendM f (Lam (Hole ty) t a) = do
ty' <- f ty
t' <- f t
return $ Lam (Hole ty') t' a
descendM f (Pi (x ::: ty) t a) = do
ty' <- f ty
t' <- f t
return $ Pi (x ::: ty') t' a
descendM f (Pi (Hole ty) t a) = do
ty' <- f ty
t' <- f t
return $ Pi (Hole ty') t' a
descendM f (App t1 t2 a) = do
return App `ap` f t1 `ap` f t2 `ap` return a
descendM f t = return t
-- | Pure bottom-up transformation on terms.
transform :: Transform t => (Expr (Id t) (A t) -> Expr (Id t) (A t)) -> t -> t
transform f = runIdentity . transformM (return . f)
descend :: Transform t => (Expr (Id t) (A t) -> Expr (Id t) (A t)) -> t -> t
descend f = runIdentity . descendM (return . f)
-- | Produces all substructures of the given term. Often useful as a generator
-- in a list comprehension.
everyone :: Transform t => t -> [Expr (Id t) (A t)]
everyone t = execState (transformM f t) [] where
f t = withState (t:) (return t)