Copyright | Copyright (c) 2016 the Hakaru team |
---|---|
License | BSD3 |
Maintainer | wren@community.haskell.org |
Stability | experimental |
Portability | GHC-only |
Safe Haskell | None |
Language | Haskell2010 |
The generating functor for the raw syntax, along with various helper types. For a more tutorial sort of introduction to how things are structured here and in Language.Hakaru.Syntax.ABT, see http://winterkoninkje.dreamwidth.org/103978.html
TODO: are we finally at the place where we can get rid of all those annoying underscores?
TODO: what is the runtime cost of storing all these dictionary singletons? For existential type variables, it should be the same as using a type class constraint; but for non-existential type variables it'll, what, double the size of the AST?
- data SCon :: [([Hakaru], Hakaru)] -> Hakaru -> * where
- Lam_ :: SCon '['('[a], b)] (a :-> b)
- App_ :: SCon '[LC (a :-> b), LC a] b
- Let_ :: SCon '[LC a, '('[a], b)] b
- CoerceTo_ :: !(Coercion a b) -> SCon '[LC a] b
- UnsafeFrom_ :: !(Coercion a b) -> SCon '[LC b] a
- PrimOp_ :: (typs ~ UnLCs args, args ~ LCs typs) => !(PrimOp typs a) -> SCon args a
- ArrayOp_ :: (typs ~ UnLCs args, args ~ LCs typs) => !(ArrayOp typs a) -> SCon args a
- MeasureOp_ :: (typs ~ UnLCs args, args ~ LCs typs) => !(MeasureOp typs a) -> SCon args (HMeasure a)
- Dirac :: SCon '[LC a] (HMeasure a)
- MBind :: SCon '[LC (HMeasure a), '('[a], HMeasure b)] (HMeasure b)
- Plate :: SCon '[LC HNat, '('[HNat], HMeasure a)] (HMeasure (HArray a))
- Chain :: SCon '[LC HNat, LC s, '('[s], HMeasure (HPair a s))] (HMeasure (HPair (HArray a) s))
- Integrate :: SCon '[LC HReal, LC HReal, '('[HReal], HProb)] HProb
- Summate :: HDiscrete a -> HSemiring b -> SCon '[LC a, LC a, '('[a], b)] b
- Product :: HDiscrete a -> HSemiring b -> SCon '[LC a, LC a, '('[a], b)] b
- Expect :: SCon '[LC (HMeasure a), '('[a], HProb)] HProb
- Observe :: SCon '[LC (HMeasure a), LC a] (HMeasure a)
- data SArgs :: ([Hakaru] -> Hakaru -> *) -> [([Hakaru], Hakaru)] -> * where
- data Term :: ([Hakaru] -> Hakaru -> *) -> Hakaru -> * where
- (:$) :: !(SCon args a) -> !(SArgs abt args) -> Term abt a
- NaryOp_ :: !(NaryOp a) -> !(Seq (abt '[] a)) -> Term abt a
- Literal_ :: !(Literal a) -> Term abt a
- Empty_ :: !(Sing (HArray a)) -> Term abt (HArray a)
- Array_ :: !(abt '[] HNat) -> !(abt '[HNat] a) -> Term abt (HArray a)
- Datum_ :: !(Datum (abt '[]) (HData' t)) -> Term abt (HData' t)
- Case_ :: !(abt '[] a) -> [Branch a abt b] -> Term abt b
- Superpose_ :: NonEmpty (abt '[] HProb, abt '[] (HMeasure a)) -> Term abt (HMeasure a)
- Reject_ :: !(Sing (HMeasure a)) -> Term abt (HMeasure a)
- type LC a = '('[], a)
- type family LCs (xs :: [Hakaru]) :: [([Hakaru], Hakaru)] where ...
- type family UnLCs (xs :: [([Hakaru], Hakaru)]) :: [Hakaru] where ...
- newtype LC_ abt a = LC_ {
- unLC_ :: abt '[] a
- data NaryOp :: Hakaru -> * where
- data PrimOp :: [Hakaru] -> Hakaru -> * where
- Not :: PrimOp '[HBool] HBool
- Impl :: PrimOp '[HBool, HBool] HBool
- Diff :: PrimOp '[HBool, HBool] HBool
- Nand :: PrimOp '[HBool, HBool] HBool
- Nor :: PrimOp '[HBool, HBool] HBool
- Pi :: PrimOp '[] HProb
- Sin :: PrimOp '[HReal] HReal
- Cos :: PrimOp '[HReal] HReal
- Tan :: PrimOp '[HReal] HReal
- Asin :: PrimOp '[HReal] HReal
- Acos :: PrimOp '[HReal] HReal
- Atan :: PrimOp '[HReal] HReal
- Sinh :: PrimOp '[HReal] HReal
- Cosh :: PrimOp '[HReal] HReal
- Tanh :: PrimOp '[HReal] HReal
- Asinh :: PrimOp '[HReal] HReal
- Acosh :: PrimOp '[HReal] HReal
- Atanh :: PrimOp '[HReal] HReal
- RealPow :: PrimOp '[HProb, HReal] HProb
- Exp :: PrimOp '[HReal] HProb
- Log :: PrimOp '[HProb] HReal
- Infinity :: HIntegrable a -> PrimOp '[] a
- GammaFunc :: PrimOp '[HReal] HProb
- BetaFunc :: PrimOp '[HProb, HProb] HProb
- Equal :: !(HEq a) -> PrimOp '[a, a] HBool
- Less :: !(HOrd a) -> PrimOp '[a, a] HBool
- NatPow :: !(HSemiring a) -> PrimOp '[a, HNat] a
- Negate :: !(HRing a) -> PrimOp '[a] a
- Abs :: !(HRing a) -> PrimOp '[a] (NonNegative a)
- Signum :: !(HRing a) -> PrimOp '[a] a
- Recip :: !(HFractional a) -> PrimOp '[a] a
- NatRoot :: !(HRadical a) -> PrimOp '[a, HNat] a
- Erf :: !(HContinuous a) -> PrimOp '[a] a
- data ArrayOp :: [Hakaru] -> Hakaru -> * where
- data MeasureOp :: [Hakaru] -> Hakaru -> * where
- Lebesgue :: MeasureOp '[] HReal
- Counting :: MeasureOp '[] HInt
- Categorical :: MeasureOp '[HArray HProb] HNat
- Uniform :: MeasureOp '[HReal, HReal] HReal
- Normal :: MeasureOp '[HReal, HProb] HReal
- Poisson :: MeasureOp '[HProb] HNat
- Gamma :: MeasureOp '[HProb, HProb] HProb
- Beta :: MeasureOp '[HProb, HProb] HProb
- data Literal :: Hakaru -> * where
- foldMapPairs :: (Monoid m, Foldable f) => (forall h i. abt h i -> m) -> f (abt xs a, abt ys b) -> m
- traversePairs :: (Applicative f, Traversable t) => (forall h i. abt1 h i -> f (abt2 h i)) -> t (abt1 xs a, abt1 ys b) -> f (t (abt2 xs a, abt2 ys b))
Syntactic forms
data SCon :: [([Hakaru], Hakaru)] -> Hakaru -> * where Source #
The constructor of a (
node in the :$
)Term
. Each of these
constructors denotes a "normal/standard/basic" syntactic
form (i.e., a generalized quantifier). In the literature, these
syntactic forms are sometimes called "operators", but we avoid
calling them that so as not to introduce confusion vs PrimOp
etc. Instead we use the term "operator" to refer to any primitive
function or constant; that is, non-binding syntactic forms. Also
in the literature, the SCon
type itself is usually called the
"signature" of the term language. However, we avoid calling
it that since our Term
has constructors other than just (:$)
,
so SCon
does not give a complete signature for our terms.
The main reason for breaking this type out and using it in
conjunction with (
and :$
)SArgs
is so that we can easily
pattern match on fully saturated nodes. For example, we want
to be able to match MeasureOp_ Uniform :$ lo :* hi :* End
without needing to deal with App_
nodes nor viewABT
.
Lam_ :: SCon '['('[a], b)] (a :-> b) | |
App_ :: SCon '[LC (a :-> b), LC a] b | |
Let_ :: SCon '[LC a, '('[a], b)] b | |
CoerceTo_ :: !(Coercion a b) -> SCon '[LC a] b | |
UnsafeFrom_ :: !(Coercion a b) -> SCon '[LC b] a | |
PrimOp_ :: (typs ~ UnLCs args, args ~ LCs typs) => !(PrimOp typs a) -> SCon args a | |
ArrayOp_ :: (typs ~ UnLCs args, args ~ LCs typs) => !(ArrayOp typs a) -> SCon args a | |
MeasureOp_ :: (typs ~ UnLCs args, args ~ LCs typs) => !(MeasureOp typs a) -> SCon args (HMeasure a) | |
Dirac :: SCon '[LC a] (HMeasure a) | |
MBind :: SCon '[LC (HMeasure a), '('[a], HMeasure b)] (HMeasure b) | |
Plate :: SCon '[LC HNat, '('[HNat], HMeasure a)] (HMeasure (HArray a)) | |
Chain :: SCon '[LC HNat, LC s, '('[s], HMeasure (HPair a s))] (HMeasure (HPair (HArray a) s)) | |
Integrate :: SCon '[LC HReal, LC HReal, '('[HReal], HProb)] HProb | |
Summate :: HDiscrete a -> HSemiring b -> SCon '[LC a, LC a, '('[a], b)] b | |
Product :: HDiscrete a -> HSemiring b -> SCon '[LC a, LC a, '('[a], b)] b | |
Expect :: SCon '[LC (HMeasure a), '('[a], HProb)] HProb | |
Observe :: SCon '[LC (HMeasure a), LC a] (HMeasure a) |
data SArgs :: ([Hakaru] -> Hakaru -> *) -> [([Hakaru], Hakaru)] -> * where Source #
The arguments to a (
node in the :$
)Term
; that is, a list
of ASTs, where the whole list is indexed by a (type-level) list
of the indices of each element.
End :: SArgs abt '[] | |
(:*) :: !(abt vars a) -> !(SArgs abt args) -> SArgs abt ('(vars, a) ': args) infixr 5 |
Traversable21 [([Hakaru], Hakaru)] Hakaru [Hakaru] SArgs Source # | |
Foldable21 [([Hakaru], Hakaru)] Hakaru [Hakaru] SArgs Source # | |
Functor21 [([Hakaru], Hakaru)] Hakaru [Hakaru] SArgs Source # | |
Eq2 Hakaru [Hakaru] abt => Eq1 [([Hakaru], Hakaru)] (SArgs abt) Source # | |
Show2 Hakaru [Hakaru] abt => Show1 [([Hakaru], Hakaru)] (SArgs abt) Source # | |
Eq2 Hakaru [Hakaru] abt => Eq (SArgs abt args) Source # | |
Show2 Hakaru [Hakaru] abt => Show (SArgs abt args) Source # | |
data Term :: ([Hakaru] -> Hakaru -> *) -> Hakaru -> * where Source #
The generating functor for Hakaru ASTs. This type is given in
open-recursive form, where the first type argument gives the
recursive form. The recursive form abt
does not have exactly
the same kind as Term abt
because every Term
represents a
locally-closed term whereas the underlying abt
may bind some
variables.
(:$) :: !(SCon args a) -> !(SArgs abt args) -> Term abt a infix 4 | |
NaryOp_ :: !(NaryOp a) -> !(Seq (abt '[] a)) -> Term abt a | |
Literal_ :: !(Literal a) -> Term abt a | |
Empty_ :: !(Sing (HArray a)) -> Term abt (HArray a) | |
Array_ :: !(abt '[] HNat) -> !(abt '[HNat] a) -> Term abt (HArray a) | |
Datum_ :: !(Datum (abt '[]) (HData' t)) -> Term abt (HData' t) | |
Case_ :: !(abt '[] a) -> [Branch a abt b] -> Term abt b | |
Superpose_ :: NonEmpty (abt '[] HProb, abt '[] (HMeasure a)) -> Term abt (HMeasure a) | |
Reject_ :: !(Sing (HMeasure a)) -> Term abt (HMeasure a) |
Traversable21 Hakaru Hakaru [Hakaru] Term Source # | |
Foldable21 Hakaru Hakaru [Hakaru] Term Source # | |
Functor21 Hakaru Hakaru [Hakaru] Term Source # | |
Show2 Hakaru [Hakaru] abt => Show1 Hakaru (Term abt) Source # | |
ABT Hakaru Term abt => Coerce (Term abt) Source # | |
Show2 Hakaru [Hakaru] abt => Show (Term abt a) Source # | |
Operators
type LC a = '('[], a) Source #
Locally closed values (i.e., not binding forms) of a given type. TODO: come up with a better name
A newtype of abt '[]
, because sometimes we need this in order
to give instances for things. In particular, this is often used
to derive the obvious Foo1 (abt '[])
instance from an underlying
Foo2 abt
instance. The primary motivating example is to give
the Datum_
branch of the Show1 (Term abt)
instance.
data NaryOp :: Hakaru -> * where Source #
Primitive associative n-ary functions. By flattening the trees
for associative operators, we can more easily perform equivalence
checking and pattern matching (e.g., to convert exp (a * log
b)
into b ** a
, regardless of whether a
is a product of
things or not). Notably, because of this encoding, we encode
things like subtraction and division by their unary operators
(negation and reciprocal).
We do not make any assumptions about whether these semigroups are monoids, commutative, idempotent, or anything else. That has to be handled by transformations, rather than by the AST itself.
data PrimOp :: [Hakaru] -> Hakaru -> * where Source #
Simple primitive functions, and constants. N.B., nothing in
here should produce or consume things of HMeasure
or HArray
type (except perhaps in a totally polymorphic way).
data ArrayOp :: [Hakaru] -> Hakaru -> * where Source #
Primitive operators for consuming or transforming arrays.
TODO: we may want to replace the Sing
arguments with something
more specific in order to capture any restrictions on what can
be stored in an array. Or, if we can get rid of them entirely
while still implementing all the use sites of
sing_ArrayOp
, that'd be
better still.
data MeasureOp :: [Hakaru] -> Hakaru -> * where Source #
Primitive operators to produce, consume, or transform
distributions/measures. This corresponds to the old Mochastic
class, except that MBind
and Superpose_
are handled elsewhere
since they are not simple operators. (Also Dirac
is handled
elsewhere since it naturally fits with MBind
, even though it
is a siple operator.)
TODO: we may want to replace the Sing
arguments with something
more specific in order to capture any restrictions on what can
be a measure space (e.g., to exclude functions). Or, if we can
get rid of them entirely while still implementing all the use
sites of sing_MeasureOp
,
that'd be better still.
Lebesgue :: MeasureOp '[] HReal | |
Counting :: MeasureOp '[] HInt | |
Categorical :: MeasureOp '[HArray HProb] HNat | |
Uniform :: MeasureOp '[HReal, HReal] HReal | |
Normal :: MeasureOp '[HReal, HProb] HReal | |
Poisson :: MeasureOp '[HProb] HNat | |
Gamma :: MeasureOp '[HProb, HProb] HProb | |
Beta :: MeasureOp '[HProb, HProb] HProb |
Constant values
data Literal :: Hakaru -> * where Source #
Numeric literals for the primitive numeric types. In addition to being normal forms, these are also ground terms: that is, not only are they closed (i.e., no free variables), they also have no bound variables and thus no binding forms. Notably, we store literals using exact types so that none of our program transformations have to worry about issues like overflow or floating-point fuzz.
implementation details
foldMapPairs :: (Monoid m, Foldable f) => (forall h i. abt h i -> m) -> f (abt xs a, abt ys b) -> m Source #
traversePairs :: (Applicative f, Traversable t) => (forall h i. abt1 h i -> f (abt2 h i)) -> t (abt1 xs a, abt1 ys b) -> f (t (abt2 xs a, abt2 ys b)) Source #