free-foil-0.3.2: Efficient Type-Safe Capture-Avoiding Substitution for Free (Scoped Monads)
Safe HaskellNone
LanguageHaskell2010

Control.Monad.Free.Foil.Annotated

Description

Annotating every node of a free foil term.

A node can be annotated with anything: a source position, a type, a memoised normal form. AnnSig turns a signature into an annotated one, and AnnAST is the annotated syntax it generates.

The annotation is a functor of the term, and that is what lets it depend on the node's scope. In AST binder sig n the signature's term parameter is the AST at the node's own scope, so an annotation built from it holds terms in that scope — which is what a type annotation in a dependent language needs. An annotation that ignores the term (a source position, say) is Const a.

Whether two annotations must agree for their nodes to match is a property of ann, not of AnnSig. Two examples, and they are the two you will want:

An annotation that ignores the term (a source position) and is compared:

instance Eq a => ZipMatchK (Const (a :: Type)) where
  zipMatchWithK _ (Const l) (Const r)
    | l == r    = Just (Const l)
    | otherwise = Nothing

An annotation that holds terms (a type, say) and is ignored, so that two terms differing only in their types are α-equivalent. Make the held term optional, so that pairing can fail without failing the match:

newtype TypeOf term = TypeOf (Maybe term)

instance ZipMatchK TypeOf where
  zipMatchWithK (f :^: M0) (TypeOf l) (TypeOf r) =
    Just (TypeOf (do { a <- l; b <- r; f a b }))

The instance must return Just unconditionally, and lazily. Matching is annotation-blind, so it must succeed whatever the annotations are; the paired annotation is a thunk the (annotation-skipping) Bifoldable never forces. A strict shape — TypeOf <$> f l r, or anything that yields Nothing when f fails — is a footgun twice over: it breaks blindness (two nodes with different types would fail to match), and it diverges for a finite or lazily-bottomed annotation (a universe tower ending in error, say), because forcing the annotation runs off the end. This is why the held term is a Maybe: a plain term field would have no value to pair when f fails, forcing a bottom into the result.

Do not reach for the generic instance here. It compares the annotation's shape, so a node carrying a memoised normal form would fail to match the same node without one. (Nor is zipMatchViaChooseLeft available: an annotation holding terms must construct a value at the result index, and cannot simply pick a side.)

Note the asymmetry in the instances below: Bifunctor and Bitraversable traverse the annotation, but Bifoldable does not. This is deliberate — see AnnSig.

Synopsis

Documentation

data AnnSig (ann :: Type -> Type) (sig :: Type -> Type -> Type) scope term Source #

A signature, with every node annotated by an ann built from the node's term.

The annotation is applied to the term parameter, so in an AST binder (AnnSig ann sig) n it holds terms in the node's own scope.

Bifoldable deliberately skips the annotation. That is what makes α-equivalence annotation-blind: alphaEquiv consumes a zipped node with bifoldMap, so a type annotation is never compared, and two terms that differ only in their annotations are α-equivalent. The price is that freeVarsOf, which is also Bifoldable, does not see variables occurring inside annotations. Use freeVarsOfAnnotated when those matter.

Constructors

AnnSig (ann term) (sig scope term) 

Instances

Instances details
Bifoldable sig => Bifoldable (AnnSig ann sig) Source #

The annotation is not folded. See AnnSig.

Instance details

Defined in Control.Monad.Free.Foil.Annotated

Methods

bifold :: Monoid m => AnnSig ann sig m m -> m #

bifoldMap :: Monoid m => (a -> m) -> (b -> m) -> AnnSig ann sig a b -> m #

bifoldr :: (a -> c -> c) -> (b -> c -> c) -> c -> AnnSig ann sig a b -> c #

bifoldl :: (c -> a -> c) -> (c -> b -> c) -> c -> AnnSig ann sig a b -> c #

(Functor ann, Bifunctor sig) => Bifunctor (AnnSig ann sig) Source # 
Instance details

Defined in Control.Monad.Free.Foil.Annotated

Methods

bimap :: (a -> b) -> (c -> d) -> AnnSig ann sig a c -> AnnSig ann sig b d #

first :: (a -> b) -> AnnSig ann sig a c -> AnnSig ann sig b c #

second :: (b -> c) -> AnnSig ann sig a b -> AnnSig ann sig a c #

(Traversable ann, Bitraversable sig) => Bitraversable (AnnSig ann sig) Source # 
Instance details

Defined in Control.Monad.Free.Foil.Annotated

Methods

bitraverse :: Applicative f => (a -> f c) -> (b -> f d) -> AnnSig ann sig a b -> f (AnnSig ann sig c d) #

(ZipMatchK ann, ZipMatchK sig) => ZipMatchK (AnnSig ann sig :: Type -> Type -> Type) Source #

Matching for AnnSig is derived, not left to the generic default.

The generic default would rebuild the Generics.Kind view of every node on every comparison, and comparing terms is most of what a typechecker does, so for an annotated signature — where it lands on the hottest path — that is a measurable cost. deriveZipMatchK2 generates the written-out instance instead: the annotation matched with the term zipper (an annotation is a functor of the term), the inner signature with both. Write deriveZipMatchK2 ''YourAnnSig for a bespoke annotated signature.

Instance details

Defined in Control.Monad.Free.Foil.Annotated

Methods

zipMatchWithK :: forall (as :: LoT (Type -> Type -> Type)) (bs :: LoT (Type -> Type -> Type)) (cs :: LoT (Type -> Type -> Type)). Mappings as bs cs -> (AnnSig ann sig :@@: as) -> (AnnSig ann sig :@@: bs) -> Maybe (AnnSig ann sig :@@: cs) Source #

GenericK (AnnSig ann sig :: Type -> Type -> Type) Source # 
Instance details

Defined in Control.Monad.Free.Foil.Annotated

Associated Types

type RepK (AnnSig ann sig :: Type -> Type -> Type) 
Instance details

Defined in Control.Monad.Free.Foil.Annotated

type RepK (AnnSig ann sig :: Type -> Type -> Type) = Field (ann :$: (Var1 :: Atom (Type -> Type -> Type) Type)) :*: Field ((sig :$: (Var0 :: Atom (Type -> Type -> Type) Type)) ':@: (Var1 :: Atom (Type -> Type -> Type) Type))

Methods

fromK :: forall (x :: LoT (Type -> Type -> Type)). (AnnSig ann sig :@@: x) -> RepK (AnnSig ann sig) x #

toK :: forall (x :: LoT (Type -> Type -> Type)). RepK (AnnSig ann sig) x -> AnnSig ann sig :@@: x #

(Foldable ann, Foldable (sig scope)) => Foldable (AnnSig ann sig scope) Source # 
Instance details

Defined in Control.Monad.Free.Foil.Annotated

Methods

fold :: Monoid m => AnnSig ann sig scope m -> m #

foldMap :: Monoid m => (a -> m) -> AnnSig ann sig scope a -> m #

foldMap' :: Monoid m => (a -> m) -> AnnSig ann sig scope a -> m #

foldr :: (a -> b -> b) -> b -> AnnSig ann sig scope a -> b #

foldr' :: (a -> b -> b) -> b -> AnnSig ann sig scope a -> b #

foldl :: (b -> a -> b) -> b -> AnnSig ann sig scope a -> b #

foldl' :: (b -> a -> b) -> b -> AnnSig ann sig scope a -> b #

foldr1 :: (a -> a -> a) -> AnnSig ann sig scope a -> a #

foldl1 :: (a -> a -> a) -> AnnSig ann sig scope a -> a #

toList :: AnnSig ann sig scope a -> [a] #

null :: AnnSig ann sig scope a -> Bool #

length :: AnnSig ann sig scope a -> Int #

elem :: Eq a => a -> AnnSig ann sig scope a -> Bool #

maximum :: Ord a => AnnSig ann sig scope a -> a #

minimum :: Ord a => AnnSig ann sig scope a -> a #

sum :: Num a => AnnSig ann sig scope a -> a #

product :: Num a => AnnSig ann sig scope a -> a #

(Traversable ann, Traversable (sig scope)) => Traversable (AnnSig ann sig scope) Source # 
Instance details

Defined in Control.Monad.Free.Foil.Annotated

Methods

traverse :: Applicative f => (a -> f b) -> AnnSig ann sig scope a -> f (AnnSig ann sig scope b) #

sequenceA :: Applicative f => AnnSig ann sig scope (f a) -> f (AnnSig ann sig scope a) #

mapM :: Monad m => (a -> m b) -> AnnSig ann sig scope a -> m (AnnSig ann sig scope b) #

sequence :: Monad m => AnnSig ann sig scope (m a) -> m (AnnSig ann sig scope a) #

(Functor ann, Functor (sig scope)) => Functor (AnnSig ann sig scope) Source # 
Instance details

Defined in Control.Monad.Free.Foil.Annotated

Methods

fmap :: (a -> b) -> AnnSig ann sig scope a -> AnnSig ann sig scope b #

(<$) :: a -> AnnSig ann sig scope b -> AnnSig ann sig scope a #

Generic (AnnSig ann sig scope term) Source # 
Instance details

Defined in Control.Monad.Free.Foil.Annotated

Associated Types

type Rep (AnnSig ann sig scope term) 
Instance details

Defined in Control.Monad.Free.Foil.Annotated

type Rep (AnnSig ann sig scope term) = D1 ('MetaData "AnnSig" "Control.Monad.Free.Foil.Annotated" "free-foil-0.3.2-Ined4vrrcdxBXWLRXM9Um9" 'False) (C1 ('MetaCons "AnnSig" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (ann term)) :*: S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (sig scope term))))

Methods

from :: AnnSig ann sig scope term -> Rep (AnnSig ann sig scope term) x #

to :: Rep (AnnSig ann sig scope term) x -> AnnSig ann sig scope term #

type RepK (AnnSig ann sig :: Type -> Type -> Type) Source # 
Instance details

Defined in Control.Monad.Free.Foil.Annotated

type RepK (AnnSig ann sig :: Type -> Type -> Type) = Field (ann :$: (Var1 :: Atom (Type -> Type -> Type) Type)) :*: Field ((sig :$: (Var0 :: Atom (Type -> Type -> Type) Type)) ':@: (Var1 :: Atom (Type -> Type -> Type) Type))
type Rep (AnnSig ann sig scope term) Source # 
Instance details

Defined in Control.Monad.Free.Foil.Annotated

type Rep (AnnSig ann sig scope term) = D1 ('MetaData "AnnSig" "Control.Monad.Free.Foil.Annotated" "free-foil-0.3.2-Ined4vrrcdxBXWLRXM9Um9" 'False) (C1 ('MetaCons "AnnSig" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (ann term)) :*: S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (sig scope term))))

type AnnAST (binder :: S -> S -> Type) (ann :: Type -> Type) (sig :: Type -> Type -> Type) = AST binder (AnnSig ann sig) Source #

An annotated scope-safe term.

type AnnScopedAST (binder :: S -> S -> Type) (ann :: Type -> Type) (sig :: Type -> Type -> Type) = ScopedAST binder (AnnSig ann sig) Source #

An annotated scope-safe term under a binder.

pattern AnnNode :: ann (AnnAST binder ann sig n) -> sig (AnnScopedAST binder ann sig n) (AnnAST binder ann sig n) -> AnnAST binder ann sig n Source #

An annotated node.

annotationOf :: forall (binder :: S -> S -> Type) ann (sig :: Type -> Type -> Type) (n :: S). AnnAST binder ann sig n -> Maybe (ann (AnnAST binder ann sig n)) Source #

The annotation of a term, unless it is a variable (which is not a node, so it carries none).

freeVarsOfAnnotated :: forall (n :: S) (binder :: S -> S -> Type) (sig :: Type -> Type -> Type) (ann :: Type -> Type). (Distinct n, CoSinkable binder, Bifoldable sig, Foldable ann) => AnnAST binder ann sig n -> [Name n] Source #

The free variables of an annotated term, including those occurring inside annotations.

freeVarsOf misses the latter, since Bifoldable skips the annotation (see AnnSig).