Portability | non-portable (-XKitchenSink) |
---|---|
Stability | experimental |
Maintainer | Stephanie Weirich <sweirich@cis.upenn.edu> |
A generic implementation of name binding functions using a locally
nameless representation. Datatypes with binding can be defined
using the Name
and Bind
types. Expressive patterns for binding
come from the Embed
and Rebind
types.
Important classes are:
Name generation is controlled via monads which implement the
Fresh
and LFresh
classes.
- data Name a
- data AnyName = forall a . Rep a => AnyName (Name a)
- data Bind p t
- newtype Embed t = Embed t
- data Rebind p1 p2
- data Rec p
- data TRec p
- newtype Shift p = Shift p
- integer2Name :: Rep a => Integer -> Name a
- string2Name :: Rep a => String -> Name a
- s2n :: Rep a => String -> Name a
- makeName :: Rep a => String -> Integer -> Name a
- name2Integer :: Name a -> Integer
- name2String :: Name a -> String
- anyName2Integer :: AnyName -> Integer
- anyName2String :: AnyName -> String
- name1 :: Rep a => Name a
- name2 :: Rep a => Name a
- name3 :: Rep a => Name a
- name4 :: Rep a => Name a
- name5 :: Rep a => Name a
- name6 :: Rep a => Name a
- name7 :: Rep a => Name a
- name8 :: Rep a => Name a
- name9 :: Rep a => Name a
- name10 :: Rep a => Name a
- translate :: Rep b => Name a -> Name b
- class (Show a, Rep1 AlphaD a) => Alpha a where
- swaps' :: AlphaCtx -> Perm AnyName -> a -> a
- fv' :: Collection f => AlphaCtx -> a -> f AnyName
- lfreshen' :: LFresh m => AlphaCtx -> a -> (a -> Perm AnyName -> m b) -> m b
- freshen' :: Fresh m => AlphaCtx -> a -> m (a, Perm AnyName)
- aeq' :: AlphaCtx -> a -> a -> Bool
- close :: Alpha b => AlphaCtx -> b -> a -> a
- open :: Alpha b => AlphaCtx -> b -> a -> a
- acompare' :: AlphaCtx -> a -> a -> Ordering
- isPat :: a -> Maybe [AnyName]
- isTerm :: a -> Bool
- isEmbed :: a -> Bool
- nthpatrec :: a -> NthCont
- findpatrec :: a -> AnyName -> FindResult
- swaps :: Alpha a => Perm AnyName -> a -> a
- swapsEmbeds :: Alpha a => Perm AnyName -> a -> a
- swapsBinders :: Alpha a => Perm AnyName -> a -> a
- aeq :: Alpha t => t -> t -> Bool
- aeqBinders :: Alpha p => p -> p -> Bool
- acompare :: Alpha t => t -> t -> Ordering
- class Foldable f => Collection f where
- newtype Multiset a = Multiset (Map a Int)
- fv :: (Rep a, Alpha t, Collection f) => t -> f (Name a)
- fvAny :: (Alpha t, Collection f) => t -> f AnyName
- patfv :: (Rep a, Alpha p, Collection f) => p -> f (Name a)
- patfvAny :: (Alpha p, Collection f) => p -> f AnyName
- binders :: (Rep a, Alpha p, Collection f) => p -> f (Name a)
- bindersAny :: (Alpha p, Collection f) => p -> f AnyName
- bind :: (Alpha c, Alpha b) => b -> c -> Bind b c
- unsafeUnbind :: (Alpha a, Alpha b) => Bind a b -> (a, b)
- class Monad m => Fresh m where
- freshen :: (Alpha p, Fresh m) => p -> m (p, Perm AnyName)
- unbind :: (Fresh m, Alpha p, Alpha t) => Bind p t -> m (p, t)
- unbind2 :: (Fresh m, Alpha p1, Alpha p2, Alpha t1, Alpha t2) => Bind p1 t1 -> Bind p2 t2 -> m (Maybe (p1, t1, p2, t2))
- unbind3 :: (Fresh m, Alpha p1, Alpha p2, Alpha p3, Alpha t1, Alpha t2, Alpha t3) => Bind p1 t1 -> Bind p2 t2 -> Bind p3 t3 -> m (Maybe (p1, t1, p2, t2, p3, t3))
- type FreshM = FreshMT Identity
- runFreshM :: FreshM a -> a
- data FreshMT m a
- runFreshMT :: Monad m => FreshMT m a -> m a
- class Monad m => LFresh m where
- lfreshen :: (Alpha p, LFresh m) => p -> (p -> Perm AnyName -> m b) -> m b
- lunbind :: (LFresh m, Alpha p, Alpha t) => Bind p t -> ((p, t) -> m c) -> m c
- lunbind2 :: (LFresh m, Alpha p1, Alpha p2, Alpha t1, Alpha t2) => Bind p1 t1 -> Bind p2 t2 -> (Maybe (p1, t1, p2, t2) -> m r) -> m r
- lunbind3 :: (LFresh m, Alpha p1, Alpha p2, Alpha p3, Alpha t1, Alpha t2, Alpha t3) => Bind p1 t1 -> Bind p2 t2 -> Bind p3 t3 -> (Maybe (p1, t1, p2, t2, p3, t3) -> m r) -> m r
- type LFreshM = LFreshMT Identity
- runLFreshM :: LFreshM a -> a
- getAvoids :: Monad m => LFreshMT m (Set AnyName)
- data LFreshMT m a
- runLFreshMT :: LFreshMT m a -> m a
- rebind :: (Alpha a, Alpha b) => a -> b -> Rebind a b
- unrebind :: (Alpha a, Alpha b) => Rebind a b -> (a, b)
- rec :: Alpha a => a -> Rec a
- unrec :: Alpha a => Rec a -> a
- trec :: Alpha p => p -> TRec p
- untrec :: (Fresh m, Alpha p) => TRec p -> m p
- luntrec :: (LFresh m, Alpha p) => TRec p -> m p
- class Rep1 (SubstD b) a => Subst b a where
- data SubstName a b where
- rName :: forall a[a18ML]. Rep a[a18ML] => R (Name a[a18ML])
- rBind :: forall p[a1f71] t[a1f72]. (Rep p[a1f71], Rep t[a1f72]) => R (Bind p[a1f71] t[a1f72])
- rRebind :: forall p1[a1f6Z] p2[a1f70]. (Rep p1[a1f6Z], Rep p2[a1f70]) => R (Rebind p1[a1f6Z] p2[a1f70])
- rEmbed :: forall t[a1f6W]. Rep t[a1f6W] => R (Embed t[a1f6W])
- rRec :: forall p[a1f6Y]. Rep p[a1f6Y] => R (Rec p[a1f6Y])
- rShift :: forall p[a1f6V]. Rep p[a1f6V] => R (Shift p[a1f6V])
Basic types
Name
s are things that get bound. This type is intentionally
abstract; to create a Name
you can use string2Name
or
integer2Name
. The type parameter is a tag, or sort, which tells
us what sorts of things this name may stand for. The sort must
be an instance of the Rep
type class.
A name with a hidden (existentially quantified) sort.
The type of a binding. We can Bind
an a
object in a b
object if we can create "fresh" a
objects, and a
objects
can occur unbound in b
objects. Often a
is Name
but that
need not be the case.
Like Name
, Bind
is also abstract. You can create bindings
using bind
and take them apart with unbind
and friends.
(Rep p[a1f71], Rep t[a1f72], Sat (ctx[a1fbG] p[a1f71]), Sat (ctx[a1fbG] t[a1f72])) => Rep1 ctx[a1fbG] (Bind p[a1f71] t[a1f72]) | |
(Subst c b, Subst c a, Alpha a, Alpha b) => Subst c (Bind a b) | |
(Alpha a, Alpha b, Read a, Read b) => Read (Bind a b) | |
(Show a, Show b) => Show (Bind a b) | |
(Rep p[a1f71], Rep t[a1f72]) => Rep (Bind p[a1f71] t[a1f72]) | |
(Alpha p, Alpha t) => Alpha (Bind p t) |
An annotation is a "hole" in a pattern where variables can be used, but not bound. For example, patterns may include type annotations, and those annotations can reference variables without binding them. Annotations do nothing special when they appear elsewhere in terms.
Embed t |
Rebind
supports "telescopes" --- that is, patterns where
bound variables appear in multiple subterms.
(Rep p1[a1f6Z], Rep p2[a1f70], Sat (ctx[a1fbl] p1[a1f6Z]), Sat (ctx[a1fbl] p2[a1f70])) => Rep1 ctx[a1fbl] (Rebind p1[a1f6Z] p2[a1f70]) | |
(Subst c b, Subst c a, Alpha a, Alpha b) => Subst c (Rebind a b) | |
(Alpha a, Alpha b, Eq b) => Eq (Rebind a b) | Compare for alpha-equality. |
(Show a, Show b) => Show (Rebind a b) | |
(Rep p1[a1f6Z], Rep p2[a1f70]) => Rep (Rebind p1[a1f6Z] p2[a1f70]) | |
(Alpha p, Alpha q) => Alpha (Rebind p q) |
Rec
supports recursive patterns --- that is, patterns where
any variables anywhere in the pattern are bound in the pattern
itself. Useful for lectrec (and Agda's dot notation).
Shift the scope of an embedded term one level outwards.
Shift p |
Utilities
makeName :: Rep a => String -> Integer -> Name aSource
Create a Name
from a String
and an Integer
index.
name2Integer :: Name a -> IntegerSource
Get the integer index of a Name
.
name2String :: Name a -> StringSource
Get the string part of a Name
.
anyName2Integer :: AnyName -> IntegerSource
Get the integer index of an AnyName
.
anyName2String :: AnyName -> StringSource
Get the string part of an AnyName
.
The Alpha
class
class (Show a, Rep1 AlphaD a) => Alpha a whereSource
The Alpha
type class is for types which may contain names. The
Rep1
constraint means that we can only make instances of this
class for types that have generic representations (which can be
automatically derived by RepLib.)
Note that the methods of Alpha
should never be called directly!
Instead, use other methods provided by this module which are
defined in terms of Alpha
methods. (The only reason they are
exported is to make them available to automatically-generated
code.)
Most of the time, the default definitions of these methods will suffice, so you can make an instance for your data type by simply declaring
instance Alpha MyType
swaps' :: AlphaCtx -> Perm AnyName -> a -> aSource
See swaps
.
fv' :: Collection f => AlphaCtx -> a -> f AnyNameSource
See fv
.
lfreshen' :: LFresh m => AlphaCtx -> a -> (a -> Perm AnyName -> m b) -> m bSource
See lfreshen
.
freshen' :: Fresh m => AlphaCtx -> a -> m (a, Perm AnyName)Source
See freshen
.
aeq' :: AlphaCtx -> a -> a -> BoolSource
See aeq
.
close :: Alpha b => AlphaCtx -> b -> a -> aSource
Replace free names by bound names.
open :: Alpha b => AlphaCtx -> b -> a -> aSource
Replace bound names by free names.
acompare' :: AlphaCtx -> a -> a -> OrderingSource
See acompare
.
isPat :: a -> Maybe [AnyName]Source
isPat x
dynamically checks whether x
can be used as a valid
pattern. The default instance returns True
if at all
possible.
isTerm x
dynamically checks whether x
can be used as a
valid term. The default instance returns True
if at all
possible.
isEmbed
is needed internally for the implementation of
isPat
. isEmbed
is true for terms wrapped in Embed
and zero
or more occurrences of Shift
. The default implementation
simply returns False
.
nthpatrec :: a -> NthContSource
looks up the nthpatrec
p nn
th name in the pattern p
(zero-indexed), returning the number of names encountered if not
found.
findpatrec :: a -> AnyName -> FindResultSource
Find the (first) index of the name in the pattern if one exists; otherwise, return the number of names encountered instead.
Alpha Bool | |
Alpha Char | |
Alpha Double | |
Alpha Float | |
Alpha Int | |
Alpha Integer | |
Alpha () | |
Alpha AnyName | |
Alpha a => Alpha [a] | |
Rep a => Alpha (R a) | |
Alpha a => Alpha (Maybe a) | |
Rep a => Alpha (Name a) | |
Alpha a => Alpha (Shift a) | |
Alpha t => Alpha (Embed t) | |
Alpha p => Alpha (Rec p) | |
(Alpha a, Alpha b) => Alpha (Either a b) | |
(Alpha a, Alpha b) => Alpha (a, b) | |
(Alpha p, Alpha q) => Alpha (Rebind p q) | |
(Alpha p, Alpha t) => Alpha (Bind p t) | |
(Alpha a, Alpha b, Alpha c) => Alpha (a, b, c) | |
(Alpha a, Alpha b, Alpha c, Alpha d) => Alpha (a, b, c, d) | |
(Alpha a, Alpha b, Alpha c, Alpha d, Alpha e) => Alpha (a, b, c, d, e) |
swapsEmbeds :: Alpha a => Perm AnyName -> a -> aSource
Apply a permutation to the annotations in a pattern. Binding names are left alone by the permutation.
swapsBinders :: Alpha a => Perm AnyName -> a -> aSource
Apply a permutation to the binding variables in a pattern. Embedded terms are left alone by the permutation.
aeqBinders :: Alpha p => p -> p -> BoolSource
Determine (alpha-)equivalence of patterns. Do they bind the same variables and have alpha-equal annotations?
acompare :: Alpha t => t -> t -> OrderingSource
An alpha-respecting total order on terms involving binders.
Variable calculations
class Foldable f => Collection f whereSource
Collections are foldable types that support empty, singleton, union, and map operations. The result of a free variable calculation may be any collection. Instances are provided for lists and sets.
Collection [] | Lists are containers under concatenation. Lists preserve ordering and multiplicity of elements. |
Collection Set | Sets are containers under union, which preserve only occurrence, not multiplicity or ordering. |
Collection Multiset | Multisets are containers which preserve multiplicity but not ordering. |
A simple representation of multisets.
Foldable Multiset | |
Collection Multiset | Multisets are containers which preserve multiplicity but not ordering. |
fv :: (Rep a, Alpha t, Collection f) => t -> f (Name a)Source
Calculate the free variables of a particular sort contained in a term.
fvAny :: (Alpha t, Collection f) => t -> f AnyNameSource
Calculate the free variables (of any sort) contained in a term.
patfv :: (Rep a, Alpha p, Collection f) => p -> f (Name a)Source
Calculate the variables of a particular sort that occur freely in pattern annotations (but are not bound by the pattern).
patfvAny :: (Alpha p, Collection f) => p -> f AnyNameSource
Calculate the variables (of any sort) that occur freely within pattern annotations (but are not bound by the pattern).
binders :: (Rep a, Alpha p, Collection f) => p -> f (Name a)Source
Calculate the binding variables (of a particular sort) in a pattern.
bindersAny :: (Alpha p, Collection f) => p -> f AnyNameSource
Calculate the binding variables (of any sort) in a pattern.
Binding operations
bind :: (Alpha c, Alpha b) => b -> c -> Bind b cSource
A smart constructor for binders, also sometimes known as "close".
unsafeUnbind :: (Alpha a, Alpha b) => Bind a b -> (a, b)Source
A destructor for binders that does not guarantee fresh names for the binders.
The Fresh
class
class Monad m => Fresh m whereSource
Fresh m => Fresh (ListT m) | |
Fresh m => Fresh (MaybeT m) | |
Fresh m => Fresh (IdentityT m) | |
Monad m => Fresh (FreshMT m) | |
Fresh m => Fresh (ContT r m) | |
(Error e, Fresh m) => Fresh (ErrorT e m) | |
Fresh m => Fresh (ReaderT r m) | |
Fresh m => Fresh (StateT s m) | |
Fresh m => Fresh (StateT s m) | |
(Monoid w, Fresh m) => Fresh (WriterT w m) | |
(Monoid w, Fresh m) => Fresh (WriterT w m) |
unbind :: (Fresh m, Alpha p, Alpha t) => Bind p t -> m (p, t)Source
Unbind (also known as "open") is the destructor for bindings. It ensures that the names in the binding are fresh.
unbind2 :: (Fresh m, Alpha p1, Alpha p2, Alpha t1, Alpha t2) => Bind p1 t1 -> Bind p2 t2 -> m (Maybe (p1, t1, p2, t2))Source
Unbind two terms with the same fresh names, provided the binders have the same number of binding variables.
unbind3 :: (Fresh m, Alpha p1, Alpha p2, Alpha p3, Alpha t1, Alpha t2, Alpha t3) => Bind p1 t1 -> Bind p2 t2 -> Bind p3 t3 -> m (Maybe (p1, t1, p2, t2, p3, t3))Source
Unbind three terms with the same fresh names, provided the binders have the same number of binding variables.
The FreshM
monad transformer. Keeps track of the lowest index
still globally unused, and increments the index every time it is
asked for a fresh name.
MonadTrans FreshMT | |
MonadError e m => MonadError e (FreshMT m) | |
MonadReader r m => MonadReader r (FreshMT m) | |
Monad m => MonadState Integer (FreshMT m) | |
MonadState s m => MonadState s (FreshMT m) | |
Monad m => Monad (FreshMT m) | |
Functor m => Functor (FreshMT m) | |
MonadPlus m => MonadPlus (FreshMT m) | |
(Monad m, Functor m) => Applicative (FreshMT m) | |
MonadIO m => MonadIO (FreshMT m) | |
MonadCont m => MonadCont (FreshMT m) | |
Monad m => Fresh (FreshMT m) |
runFreshMT :: Monad m => FreshMT m a -> m aSource
Run a FreshMT
computation starting in an empty context.
The LFresh
class
class Monad m => LFresh m whereSource
This is the class of monads that support freshness in an (implicit) local scope. Generated names are fresh for the current local scope, but not globally fresh.
lfresh :: Rep a => Name a -> m (Name a)Source
Pick a new name that is fresh for the current (implicit) scope.
avoid :: [AnyName] -> m a -> m aSource
Avoid the given names when freshening in the subcomputation.
LFresh m => LFresh (ListT m) | |
LFresh (Reader Integer) | A simple reader monad instance for |
LFresh m => LFresh (MaybeT m) | |
LFresh m => LFresh (IdentityT m) | |
Monad m => LFresh (LFreshMT m) | |
LFresh m => LFresh (ContT r m) | |
(Error e, LFresh m) => LFresh (ErrorT e m) | |
LFresh m => LFresh (ReaderT r m) | |
LFresh m => LFresh (StateT s m) | |
LFresh m => LFresh (StateT s m) | |
(Monoid w, LFresh m) => LFresh (WriterT w m) | |
(Monoid w, LFresh m) => LFresh (WriterT w m) |
lfreshen :: (Alpha p, LFresh m) => p -> (p -> Perm AnyName -> m b) -> m bSource
"Locally" freshen a pattern replacing all binding names with new names that have not already been used. The second argument is a continuation, which takes the renamed term and a permutation that specifies how the pattern has been renamed.
lunbind :: (LFresh m, Alpha p, Alpha t) => Bind p t -> ((p, t) -> m c) -> m cSource
Destruct a binding in an LFresh
monad.
lunbind2 :: (LFresh m, Alpha p1, Alpha p2, Alpha t1, Alpha t2) => Bind p1 t1 -> Bind p2 t2 -> (Maybe (p1, t1, p2, t2) -> m r) -> m rSource
Unbind two terms with the same fresh names, provided the binders have the same number of binding variables.
lunbind3 :: (LFresh m, Alpha p1, Alpha p2, Alpha p3, Alpha t1, Alpha t2, Alpha t3) => Bind p1 t1 -> Bind p2 t2 -> Bind p3 t3 -> (Maybe (p1, t1, p2, t2, p3, t3) -> m r) -> m rSource
Unbind three terms with the same fresh names, provided the binders have the same number of binding variables.
type LFreshM = LFreshMT IdentitySource
A convenient monad which is an instance of LFresh
. It keeps
track of a set of names to avoid, and when asked for a fresh one
will choose the first unused numerical name.
runLFreshM :: LFreshM a -> aSource
Run a LFreshM computation in an empty context.
The LFresh monad transformer. Keeps track of a set of names to avoid, and when asked for a fresh one will choose the first unused numerical name.
MonadTrans LFreshMT | |
MonadError e m => MonadError e (LFreshMT m) | |
MonadReader r m => MonadReader r (LFreshMT m) | |
MonadState s m => MonadState s (LFreshMT m) | |
Monad m => Monad (LFreshMT m) | |
Functor m => Functor (LFreshMT m) | |
MonadPlus m => MonadPlus (LFreshMT m) | |
Applicative m => Applicative (LFreshMT m) | |
MonadIO m => MonadIO (LFreshMT m) | |
MonadCont m => MonadCont (LFreshMT m) | |
Monad m => LFresh (LFreshMT m) | |
Monad m => MonadReader (Set AnyName) (LFreshMT m) |
runLFreshMT :: LFreshMT m a -> m aSource
Run an LFreshMT
computation in an empty context.
Rebinding operations
Rec operations
Substitution
class Rep1 (SubstD b) a => Subst b a whereSource
The Subst
class governs capture-avoiding substitution. To
derive this class, you only need to indicate where the variables
are in the data type, by overriding the method isvar
.
isvar :: a -> Maybe (SubstName a b)Source
If the argument is a variable, return its name wrapped in the
SubstName
constructor. Return Nothing
for non-variable
arguments. The default implementation always returns
Nothing
.
subst :: Name b -> b -> a -> aSource
substitutes subst
nm sub tmsub
for nm
in tm
.
substs :: [(Name b, b)] -> a -> aSource
Perform several simultaneous substitutions.
Subst b AnyName | |
Subst b Double | |
Subst b Float | |
Subst b Integer | |
Subst b Char | |
Subst b () | |
Subst b Bool | |
Subst b Int | |
(Alpha a, Subst c a) => Subst c (Rec a) | |
Subst c a => Subst c (Embed a) | |
Subst c a => Subst c (Maybe a) | |
Subst c a => Subst c [a] | |
Rep a => Subst b (Name a) | |
Rep a => Subst b (R a) | |
(Subst c b, Subst c a, Alpha a, Alpha b) => Subst c (Rebind a b) | |
(Subst c b, Subst c a, Alpha a, Alpha b) => Subst c (Bind a b) | |
(Subst c a, Subst c b) => Subst c (Either a b) | |
(Subst c a, Subst c b) => Subst c (a, b) | |
(Subst c a, Subst c b, Subst c d) => Subst c (a, b, d) | |
(Subst c a, Subst c b, Subst c d, Subst c e) => Subst c (a, b, d, e) | |
(Subst c a, Subst c b, Subst c d, Subst c e, Subst c f) => Subst c (a, b, d, e, f) |
Pay no attention to the man behind the curtain
These type representation objects are exported so they can be referenced by auto-generated code. Please pretend they do not exist.