syntactic-3.7: Generic representation and manipulation of abstract syntax

Safe HaskellNone
LanguageHaskell2010

Language.Syntactic.Functional

Contents

Description

Basics for implementing functional EDSLs

Synopsis

Syntactic constructs

newtype Name Source #

Variable name

Constructors

Name Integer 

Instances

Enum Name Source # 

Methods

succ :: Name -> Name #

pred :: Name -> Name #

toEnum :: Int -> Name #

fromEnum :: Name -> Int #

enumFrom :: Name -> [Name] #

enumFromThen :: Name -> Name -> [Name] #

enumFromTo :: Name -> Name -> [Name] #

enumFromThenTo :: Name -> Name -> Name -> [Name] #

Eq Name Source # 

Methods

(==) :: Name -> Name -> Bool #

(/=) :: Name -> Name -> Bool #

Integral Name Source # 

Methods

quot :: Name -> Name -> Name #

rem :: Name -> Name -> Name #

div :: Name -> Name -> Name #

mod :: Name -> Name -> Name #

quotRem :: Name -> Name -> (Name, Name) #

divMod :: Name -> Name -> (Name, Name) #

toInteger :: Name -> Integer #

Num Name Source # 

Methods

(+) :: Name -> Name -> Name #

(-) :: Name -> Name -> Name #

(*) :: Name -> Name -> Name #

negate :: Name -> Name #

abs :: Name -> Name #

signum :: Name -> Name #

fromInteger :: Integer -> Name #

Ord Name Source # 

Methods

compare :: Name -> Name -> Ordering #

(<) :: Name -> Name -> Bool #

(<=) :: Name -> Name -> Bool #

(>) :: Name -> Name -> Bool #

(>=) :: Name -> Name -> Bool #

max :: Name -> Name -> Name #

min :: Name -> Name -> Name #

Real Name Source # 

Methods

toRational :: Name -> Rational #

Show Name Source # 

Methods

showsPrec :: Int -> Name -> ShowS #

show :: Name -> String #

showList :: [Name] -> ShowS #

NFData Name Source # 

Methods

rnf :: Name -> () #

EvalEnv BindingT RunEnv Source # 

Methods

compileSym :: proxy RunEnv -> BindingT sig -> DenotationM (Reader RunEnv) sig Source #

data Literal sig where Source #

Literal

Constructors

Literal :: Show a => a -> Literal (Full a) 

data Construct sig where Source #

Generic N-ary syntactic construct

Construct gives a quick way to introduce a syntactic construct by giving its name and semantic function.

Constructors

Construct :: Signature sig => String -> Denotation sig -> Construct sig 

data Binding sig where Source #

Variables and binders

Constructors

Var :: Name -> Binding (Full a) 
Lam :: Name -> Binding (b :-> Full (a -> b)) 

Instances

NFData1 Binding Source # 

Methods

liftRnf :: (a -> ()) -> Binding a -> () #

Symbol Binding Source # 

Methods

symSig :: Binding sig -> SigRep sig Source #

StringTree Binding Source # 
Render Binding Source # 
Equality Binding Source #

equal does strict identifier comparison; i.e. no alpha equivalence.

hash assigns the same hash to all variables and binders. This is a valid over-approximation that enables the following property:

alphaEq a b ==> hash a == hash b

Methods

equal :: Binding a -> Binding b -> Bool Source #

hash :: Binding a -> Hash Source #

BindingDomain Binding Source # 

Methods

prVar :: Binding sig -> Maybe Name Source #

prLam :: Binding sig -> Maybe Name Source #

renameBind :: (Name -> Name) -> Binding sig -> Binding sig Source #

maxLam :: Project Binding s => AST s a -> Name Source #

Get the highest name bound by the first Lam binders at every path from the root. If the term has ordered binders \[1\], maxLam returns the highest name introduced in the whole term.

\[1\] Ordered binders means that the names of Lam nodes are decreasing along every path from the root.

lam_template Source #

Arguments

:: Project Binding sym 
=> (Name -> sym (Full a))

Variable symbol constructor

-> (Name -> ASTF sym b -> ASTF sym (a -> b))

Lambda constructor

-> (ASTF sym a -> ASTF sym b) 
-> ASTF sym (a -> b) 

Higher-order interface for variable binding for domains based on Binding

Assumptions:

  • The body f does not inspect its argument.
  • Applying f to a term with ordered binders results in a term with ordered binders \[1\].

\[1\] Ordered binders means that the names of Lam nodes are decreasing along every path from the root.

See "Using Circular Programs for Higher-Order Syntax" (ICFP 2013, http://www.cse.chalmers.se/~emax/documents/axelsson2013using.pdf).

lam :: Binding :<: sym => (ASTF sym a -> ASTF sym b) -> ASTF sym (a -> b) Source #

Higher-order interface for variable binding

This function is lamT_template specialized to domains sym satisfying (Binding :<: sym).

fromDeBruijn :: Binding :<: sym => ASTF sym a -> ASTF sym a Source #

Convert from a term with De Bruijn indexes to one with explicit names

In the argument term, variable Names are treated as De Bruijn indexes, and lambda Names are ignored. (Ideally, one should use a different type for De Bruijn terms.)

data BindingT sig where Source #

Typed variables and binders

Constructors

VarT :: Typeable a => Name -> BindingT (Full a) 
LamT :: Typeable a => Name -> BindingT (b :-> Full (a -> b)) 

Instances

NFData1 BindingT Source # 

Methods

liftRnf :: (a -> ()) -> BindingT a -> () #

Symbol BindingT Source # 

Methods

symSig :: BindingT sig -> SigRep sig Source #

StringTree BindingT Source # 
Render BindingT Source # 
Equality BindingT Source #

equal does strict identifier comparison; i.e. no alpha equivalence.

hash assigns the same hash to all variables and binders. This is a valid over-approximation that enables the following property:

alphaEq a b ==> hash a == hash b

Methods

equal :: BindingT a -> BindingT b -> Bool Source #

hash :: BindingT a -> Hash Source #

BindingDomain BindingT Source # 
EvalEnv BindingT RunEnv Source # 

Methods

compileSym :: proxy RunEnv -> BindingT sig -> DenotationM (Reader RunEnv) sig Source #

maxLamT :: Project BindingT sym => AST sym a -> Name Source #

Get the highest name bound by the first LamT binders at every path from the root. If the term has ordered binders \[1\], maxLamT returns the highest name introduced in the whole term.

\[1\] Ordered binders means that the names of LamT nodes are decreasing along every path from the root.

lamT_template Source #

Arguments

:: Project BindingT sym 
=> (Name -> sym (Full a))

Variable symbol constructor

-> (Name -> ASTF sym b -> ASTF sym (a -> b))

Lambda constructor

-> (ASTF sym a -> ASTF sym b) 
-> ASTF sym (a -> b) 

Higher-order interface for variable binding

Assumptions:

  • The body f does not inspect its argument.
  • Applying f to a term with ordered binders results in a term with ordered binders \[1\].

\[1\] Ordered binders means that the names of LamT nodes are decreasing along every path from the root.

See "Using Circular Programs for Higher-Order Syntax" (ICFP 2013, http://www.cse.chalmers.se/~emax/documents/axelsson2013using.pdf).

lamT :: (BindingT :<: sym, Typeable a) => (ASTF sym a -> ASTF sym b) -> ASTF sym (a -> b) Source #

Higher-order interface for variable binding

This function is lamT_template specialized to domains sym satisfying (BindingT :<: sym).

lamTyped :: (sym ~ Typed s, BindingT :<: s, Typeable a, Typeable b) => (ASTF sym a -> ASTF sym b) -> ASTF sym (a -> b) Source #

Higher-order interface for variable binding

This function is lamT_template specialized to domains sym satisfying (sym ~ Typed s, BindingT :<: s).

class BindingDomain sym where Source #

Domains that "might" include variables and binders

Minimal complete definition

prVar, prLam, renameBind

Methods

prVar :: sym sig -> Maybe Name Source #

prLam :: sym sig -> Maybe Name Source #

renameBind :: (Name -> Name) -> sym sig -> sym sig Source #

Rename a variable or a lambda (no effect for other symbols)

Instances

BindingDomain sym Source # 

Methods

prVar :: sym sig -> Maybe Name Source #

prLam :: sym sig -> Maybe Name Source #

renameBind :: (Name -> Name) -> sym sig -> sym sig Source #

BindingDomain BindingT Source # 
BindingDomain Binding Source # 

Methods

prVar :: Binding sig -> Maybe Name Source #

prLam :: Binding sig -> Maybe Name Source #

renameBind :: (Name -> Name) -> Binding sig -> Binding sig Source #

BindingDomain sym => BindingDomain (Typed sym) Source # 

Methods

prVar :: Typed sym sig -> Maybe Name Source #

prLam :: Typed sym sig -> Maybe Name Source #

renameBind :: (Name -> Name) -> Typed sym sig -> Typed sym sig Source #

BindingDomain sym => BindingDomain (AST sym) Source # 

Methods

prVar :: AST sym sig -> Maybe Name Source #

prLam :: AST sym sig -> Maybe Name Source #

renameBind :: (Name -> Name) -> AST sym sig -> AST sym sig Source #

(BindingDomain sym1, BindingDomain sym2) => BindingDomain ((:+:) sym1 sym2) Source # 

Methods

prVar :: (sym1 :+: sym2) sig -> Maybe Name Source #

prLam :: (sym1 :+: sym2) sig -> Maybe Name Source #

renameBind :: (Name -> Name) -> (sym1 :+: sym2) sig -> (sym1 :+: sym2) sig Source #

BindingDomain sym => BindingDomain ((:&:) sym i) Source # 

Methods

prVar :: (sym :&: i) sig -> Maybe Name Source #

prLam :: (sym :&: i) sig -> Maybe Name Source #

renameBind :: (Name -> Name) -> (sym :&: i) sig -> (sym :&: i) sig Source #

data Let sig where Source #

A symbol for let bindings

This symbol is just an application operator. The actual binding has to be done by a lambda that constructs the second argument.

The provided string is just a tag and has nothing to do with the name of the variable of the second argument (if that argument happens to be a lambda). However, a back end may use the tag to give a sensible name to the generated variable.

The string tag may be empty.

Constructors

Let :: String -> Let (a :-> ((a -> b) :-> Full b)) 

Instances

Symbol Let Source # 

Methods

symSig :: Let sig -> SigRep sig Source #

StringTree Let Source # 
Render Let Source # 

Methods

renderSym :: Let sig -> String Source #

renderArgs :: [String] -> Let sig -> String Source #

Equality Let Source # 

Methods

equal :: Let a -> Let b -> Bool Source #

hash :: Let a -> Hash Source #

Eval Let Source # 

Methods

evalSym :: Let sig -> Denotation sig Source #

EvalEnv Let env Source # 

Methods

compileSym :: proxy env -> Let sig -> DenotationM (Reader env) sig Source #

data MONAD m sig where Source #

Monadic constructs

See "Generic Monadic Constructs for Embedded Languages" (Persson et al., IFL 2011 http://www.cse.chalmers.se/~emax/documents/persson2011generic.pdf).

Constructors

Return :: MONAD m (a :-> Full (m a)) 
Bind :: MONAD m (m a :-> ((a -> m b) :-> Full (m b))) 

Instances

Symbol (MONAD m) Source # 

Methods

symSig :: MONAD m sig -> SigRep sig Source #

StringTree (MONAD m) Source # 
Render (MONAD m) Source # 

Methods

renderSym :: MONAD m sig -> String Source #

renderArgs :: [String] -> MONAD m sig -> String Source #

Equality (MONAD m) Source # 

Methods

equal :: MONAD m a -> MONAD m b -> Bool Source #

hash :: MONAD m a -> Hash Source #

Monad m => Eval (MONAD m) Source # 

Methods

evalSym :: MONAD m sig -> Denotation sig Source #

Monad m => EvalEnv (MONAD m) env Source # 

Methods

compileSym :: proxy env -> MONAD m sig -> DenotationM (Reader env) sig Source #

newtype Remon sym m a where Source #

Reifiable monad

See "Generic Monadic Constructs for Embedded Languages" (Persson et al., IFL 2011 http://www.cse.chalmers.se/~emax/documents/persson2011generic.pdf).

It is advised to convert to/from Remon using the Syntactic instance provided in the modules Language.Syntactic.Sugar.Monad or Language.Syntactic.Sugar.MonadT.

Constructors

Remon :: {..} -> Remon sym m a 

Fields

Instances

Monad (Remon dom m) Source # 

Methods

(>>=) :: Remon dom m a -> (a -> Remon dom m b) -> Remon dom m b #

(>>) :: Remon dom m a -> Remon dom m b -> Remon dom m b #

return :: a -> Remon dom m a #

fail :: String -> Remon dom m a #

Functor (Remon sym m) Source # 

Methods

fmap :: (a -> b) -> Remon sym m a -> Remon sym m b #

(<$) :: a -> Remon sym m b -> Remon sym m a #

Applicative (Remon sym m) Source # 

Methods

pure :: a -> Remon sym m a #

(<*>) :: Remon sym m (a -> b) -> Remon sym m a -> Remon sym m b #

(*>) :: Remon sym m a -> Remon sym m b -> Remon sym m b #

(<*) :: Remon sym m a -> Remon sym m b -> Remon sym m a #

type Domain (Remon sym m a) Source # 
type Domain (Remon sym m a) = sym
type Domain (Remon sym m a) Source # 
type Domain (Remon sym m a) = sym
type Internal (Remon sym m a) Source # 
type Internal (Remon sym m a) = m (Internal a)
type Internal (Remon sym m a) Source # 
type Internal (Remon sym m a) = m (Internal a)

desugarMonad :: (MONAD m :<: sym, Typeable a, Typeable m) => Remon sym m (ASTF sym a) -> ASTF sym (m a) Source #

One-layer desugaring of monadic actions

desugarMonadTyped :: (MONAD m :<: s, sym ~ Typed s, Typeable a, Typeable m) => Remon sym m (ASTF sym a) -> ASTF sym (m a) Source #

One-layer desugaring of monadic actions

Free and bound variables

freeVars :: BindingDomain sym => AST sym sig -> Set Name Source #

Get the set of free variables in an expression

allVars :: BindingDomain sym => AST sym sig -> Set Name Source #

Get the set of variables (free, bound and introduced by lambdas) in an expression

renameUnique' :: forall sym a. BindingDomain sym => [Name] -> ASTF sym a -> ASTF sym a Source #

Rename the bound variables in a term

The free variables are left untouched. The bound variables are given unique names using as small names as possible. The first argument is a list of reserved names. Reserved names and names of free variables are not used when renaming bound variables.

renameUnique :: BindingDomain sym => ASTF sym a -> ASTF sym a Source #

Rename the bound variables in a term

The free variables are left untouched. The bound variables are given unique names using as small names as possible. Names of free variables are not used when renaming bound variables.

Alpha-equivalence

type AlphaEnv = [(Name, Name)] Source #

Environment used by alphaEq'

alphaEq' :: (Equality sym, BindingDomain sym) => AlphaEnv -> ASTF sym a -> ASTF sym b -> Bool Source #

alphaEq :: (Equality sym, BindingDomain sym) => ASTF sym a -> ASTF sym b -> Bool Source #

Alpha-equivalence

Evaluation

type family Denotation sig Source #

Semantic function type of the given symbol signature

Instances

type Denotation (Full a) Source # 
type Denotation (Full a) = a
type Denotation ((:->) a sig) Source # 
type Denotation ((:->) a sig) = a -> Denotation sig

class Eval s where Source #

Minimal complete definition

evalSym

Methods

evalSym :: s sig -> Denotation sig Source #

Instances

Eval Empty Source # 

Methods

evalSym :: Empty sig -> Denotation sig Source #

Eval Let Source # 

Methods

evalSym :: Let sig -> Denotation sig Source #

Eval Construct Source # 

Methods

evalSym :: Construct sig -> Denotation sig Source #

Eval Literal Source # 

Methods

evalSym :: Literal sig -> Denotation sig Source #

Eval BindingWS Source # 

Methods

evalSym :: BindingWS sig -> Denotation sig Source #

Eval Tuple Source # 

Methods

evalSym :: Tuple sig -> Denotation sig Source #

Monad m => Eval (MONAD m) Source # 

Methods

evalSym :: MONAD m sig -> Denotation sig Source #

Eval sym => Eval (ReaderSym sym) Source # 

Methods

evalSym :: ReaderSym sym sig -> Denotation sig Source #

(Eval s, Eval t) => Eval ((:+:) s t) Source # 

Methods

evalSym :: (s :+: t) sig -> Denotation sig Source #

Eval sym => Eval ((:&:) sym info) Source # 

Methods

evalSym :: (sym :&: info) sig -> Denotation sig Source #

evalDen :: Eval s => AST s sig -> Denotation sig Source #

Evaluation

type family DenotationM (m :: * -> *) sig Source #

Monadic denotation; mapping from a symbol signature

a :-> b :-> Full c

to

m a -> m b -> m c

Instances

type DenotationM m (Full a) Source # 
type DenotationM m (Full a) = m a
type DenotationM m ((:->) a sig) Source # 
type DenotationM m ((:->) a sig) = m a -> DenotationM m sig

liftDenotationM :: forall m sig proxy1 proxy2. Monad m => SigRep sig -> proxy1 m -> proxy2 sig -> Denotation sig -> DenotationM m sig Source #

type RunEnv = [(Name, Dynamic)] Source #

Runtime environment

class EvalEnv sym env where Source #

Evaluation

Methods

compileSym :: proxy env -> sym sig -> DenotationM (Reader env) sig Source #

compileSym :: (Symbol sym, Eval sym) => proxy env -> sym sig -> DenotationM (Reader env) sig Source #

Instances

EvalEnv Empty env Source # 

Methods

compileSym :: proxy env -> Empty sig -> DenotationM (Reader env) sig Source #

EvalEnv Let env Source # 

Methods

compileSym :: proxy env -> Let sig -> DenotationM (Reader env) sig Source #

EvalEnv BindingT RunEnv Source # 

Methods

compileSym :: proxy RunEnv -> BindingT sig -> DenotationM (Reader RunEnv) sig Source #

EvalEnv Construct env Source # 

Methods

compileSym :: proxy env -> Construct sig -> DenotationM (Reader env) sig Source #

EvalEnv Literal env Source # 

Methods

compileSym :: proxy env -> Literal sig -> DenotationM (Reader env) sig Source #

EvalEnv Tuple env Source # 

Methods

compileSym :: proxy env -> Tuple sig -> DenotationM (Reader env) sig Source #

EvalEnv sym env => EvalEnv (Typed sym) env Source # 

Methods

compileSym :: proxy env -> Typed sym sig -> DenotationM (Reader env) sig Source #

Monad m => EvalEnv (MONAD m) env Source # 

Methods

compileSym :: proxy env -> MONAD m sig -> DenotationM (Reader env) sig Source #

(EvalEnv sym1 env, EvalEnv sym2 env) => EvalEnv ((:+:) sym1 sym2) env Source # 

Methods

compileSym :: proxy env -> (sym1 :+: sym2) sig -> DenotationM (Reader env) sig Source #

EvalEnv sym env => EvalEnv ((:&:) sym info) env Source # 

Methods

compileSym :: proxy env -> (sym :&: info) sig -> DenotationM (Reader env) sig Source #

compileSymDefault :: forall proxy env sym sig. Eval sym => SigRep sig -> proxy env -> sym sig -> DenotationM (Reader env) sig Source #

Simple implementation of compileSym from a Denotation

evalOpen :: EvalEnv sym env => env -> ASTF sym a -> a Source #

Evaluation of open terms

evalClosed :: EvalEnv sym RunEnv => ASTF sym a -> a Source #

Evaluation of closed terms where RunEnv is used as the internal environment

(Note that there is no guarantee that the term is actually closed.)