Why make the product of distributions out of a list? Will an ordinary tuple (the product of two types) work in place of :*:
?
{-# LANGUAGE TypeOperators,TypeFamilies #-}
class Distribution m where
type SampleSpace m :: *
data (:+:) a b = ProductSampleSpaceWhatever
deriving (Show)
instance (Distribution m1, Distribution m2) => Distribution (m1, m2) where
type SampleSpace (m1, m2) = SampleSpace m1 :+: SampleSpace m2
data NormalDistribution = NormalDistributionWhatever
instance Distribution NormalDistribution where
type SampleSpace NormalDistribution = Doubles
data ExponentialDistribution = ExponentialDistributionWhatever
instance Distribution ExponentialDistribution where
type SampleSpace ExponentialDistribution = Doubles
data Doubles = DoublesSampleSpaceWhatever
example :: SampleSpace (NormalDistribution, ExponentialDistribution)
example = ProductSampleSpaceWhatever
example' :: Doubles :+: Doubles
example' = example
-- Just to prove it works:
main = print example'
The difference between a tree of tuples and a list is that trees of tuples are magma-like (there's a binary operator), while lists are monoid-like (there's a binary operator, an identity, and the operator is associative). So there's no single, picked out DNil
that is the identity, and the type doesn't force us to discard the difference between (NormalDistribution :*: ExponentialDistribution) :*: BinaryDistribution
and NormalDistribution :*: (ExponentialDistribution :*: BinaryDistribution)
.
Edit
The following code makes type lists with an associative operator, TypeListConcat
, and an identity, TypeListNil
. Nothing guarantees that there won't be other instances of TypeList
than the two types provided. I couldn't get TypeOperators
syntax to work for everything I'd like it to.
{-# LANGUAGE TypeFamilies,MultiParamTypeClasses,FlexibleInstances,TypeOperators #-}
-- Lists of types
-- The class of things where the end of them can be replaced with something
-- The extra parameter t combined with FlexibleInstances lets us get away with essentially
-- type TypeListConcat :: * -> *
-- And instances with a free variable for the first argument
class TypeList l a where
type TypeListConcat l a :: *
typeListConcat :: l -> a -> TypeListConcat l a
-- An identity for a list of types. Nothing guarantees it is unique
data TypeListNil = TypeListNil
deriving (Show)
instance TypeList TypeListNil a where
type TypeListConcat TypeListNil a = a
typeListConcat TypeListNil a = a
-- Cons for a list of types, nothing guarantees it is unique.
data (:::) h t = (:::) h t
deriving (Show)
infixr 5 :::
instance (TypeList t a) => TypeList (h ::: t) a where
type TypeListConcat (h ::: t) a = h ::: (TypeListConcat t a)
typeListConcat (h ::: t) a = h ::: (typeListConcat t a)
-- A Distribution instance for lists of types
class Distribution m where
type SampleSpace m :: *
instance Distribution TypeListNil where
type SampleSpace TypeListNil = TypeListNil
instance (Distribution m1, Distribution m2) => Distribution (m1 ::: m2) where
type SampleSpace (m1 ::: m2) = SampleSpace m1 ::: SampleSpace m2
-- Some types and values to play with
data NormalDistribution = NormalDistributionWhatever
instance Distribution NormalDistribution where
type SampleSpace NormalDistribution = Doubles
data ExponentialDistribution = ExponentialDistributionWhatever
instance Distribution ExponentialDistribution where
type SampleSpace ExponentialDistribution = Doubles
data BinaryDistribution = BinaryDistributionWhatever
instance Distribution BinaryDistribution where
type SampleSpace BinaryDistribution = Bools
data Doubles = DoublesSampleSpaceWhatever
deriving (Show)
data Bools = BoolSampleSpaceWhatever
deriving (Show)
-- Play with them
example1 :: TypeListConcat (Doubles ::: TypeListNil) (Doubles ::: Bools ::: TypeListNil)
example1 = (DoublesSampleSpaceWhatever ::: TypeListNil) `typeListConcat` (DoublesSampleSpaceWhatever ::: BoolSampleSpaceWhatever ::: TypeListNil)
example2 :: TypeListConcat (Doubles ::: Doubles ::: TypeListNil) (Bools ::: TypeListNil)
example2 = example2
example3 :: Doubles ::: Doubles ::: Bools ::: TypeListNil
example3 = example1
example4 :: SampleSpace (NormalDistribution ::: ExponentialDistribution ::: BinaryDistribution ::: TypeListNil)
example4 = example3
main = print example4
Edit - code using TypeList
s
Here's some code that is similar to the code you added in your edit. I couldn't figure out what Rand
is supposed to be, so I made up something else.
-- Distributions with sampling
class Distribution m => Generative m where
generate :: m -> StdGen -> (SampleSpace m, StdGen)
instance Generative TypeListNil where
generate TypeListNil g = (TypeListNil, g)
instance (Generative m1, Generative m2) => Generative (m1 ::: m2) where
generate (m ::: ms) g =
let
(x, g') = generate m g
(xs, g'') = generate ms g'
in (x ::: xs, g'')
-- Distributions with modes
class Distribution m => Modal m where
modes :: m -> [SampleSpace m]
instance Modal TypeListNil where
modes TypeListNil = [TypeListNil]
instance (Modal m1, Modal m2) => Modal (m1 ::: m2) where
modes (m ::: ms) = [ x ::: xs | x <- modes m, xs <- modes ms]