diff --git a/Data/Distribution.hs b/Data/Distribution.hs
new file mode 100644
--- /dev/null
+++ b/Data/Distribution.hs
@@ -0,0 +1,175 @@
+{- Copyright 2014 Romain Edelmann
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License. -}
+
+-- | This module defines finite discrete probability distributions
+--   and efficient ways to construct, modify, combine, measure and sample them.
+--
+--   The various functionalities are each defined in their own submodules and
+--   simply re-exported here. Note that not all modules in the package are
+--   directly exported by this top-level module.
+module Data.Distribution
+    ( -- * Exported modules
+
+      module Data.Distribution.Core
+      -- | The "Data.Distribution.Core" module contains the definition of
+      --   finite discrete probability distributions, as well as functions for
+      --   constructing, deconstructing and combining such distributions.
+
+    , module Data.Distribution.Measure
+      -- | The "Data.Distribution.Measure" module contains functions to measure
+      --   the 'probability' of events, the 'expectation' and 'variance' of
+      --   numeric distributions as well as functions for getting interesting
+      --   values, such as 'median', 'quantile's and 'modes', out of
+      --   distributions.
+
+    , module Data.Distribution.Aggregator
+      -- | The "Data.Distribution.Aggregator" module provides way to modify
+      --   the probabilities of lists of values tagged with their probability.
+      --   The module also defines common aggregators such as 'complementary'
+      --   or 'cumulative'.
+
+    , module Data.Distribution.Sample
+      -- | The "Data.Distribution.Sample" module provides ways to efficiently
+      --   randomly sample values from distributions.
+
+      -- * Other modules
+
+      -- | Not all modules related to distributions are exported by default.
+      --   Here is a list of such modules:
+      --
+      --       * "Data.Distribution.Plot" : For plotting distributions.
+      --                                    This module is part of the
+      --                                    @distribution-plot@ package.
+      --
+      --       * "Data.Distribution.Domain.Dice" : Distributions over dice.
+      --
+      --       * "Data.Distribution.Domain.Coin" : Distributions over coins.
+
+      -- * Usage
+
+      -- ** Basics
+
+      -- | To illustrate how to use the module, let's walk through some simple
+      --   examples. Let us first create a uniform distribution over the
+      --   integers from 1 to 4.
+      --
+      --   >>> uniform [1 .. 4]
+      --   fromList [(1,1 % 4),(2,1 % 4),(3,1 % 4),(4,1 % 4)]
+      --
+      --   The textual representation of distributions lists every value in the
+      --   distribution with non-zero probability, in ascending order. To each
+      --   value is associated its probability in the distribution.
+      --
+      --   We can use the 'probability' function to get the probability of some
+      --   predicate in the distribution.
+      --
+      --   >>> probability (>= 2) $ uniform [1 .. 4]
+      --   3 % 4
+      --   >>> probability (< 1) $ uniform [1 .. 4]
+      --   0 % 1
+
+      -- ** Measures
+
+      -- | We can also compute some other measures on the distributions, such
+      --   as for instance 'expectation' and 'variance'.
+      --   (For more details, see "Data.Distribution.Measure")
+      --
+      --   >>> expectation $ uniform [1 .. 4]
+      --   2.5
+      --   >>> variance $ uniform [1 .. 4]
+      --   1.25
+
+      -- ** Transforming distributions
+
+      -- | Distributions can be transformed and combined in various ways.
+      --   For instance, to apply a function on the values in a distribution
+      --   'select' can be used.
+      --   (For more details, see "Data.Distribution.Core")
+      --
+      --   >>> select (\ x -> x * x) $ uniform [-2, 0, 2]
+      --   fromList [(0,1 % 3),(4,2 % 3)]
+      --   >>> select (> 3) $ uniform [1 .. 10]
+      --   fromList [(False,3 % 10),(True,7 % 10)]
+      --
+      --   The 'andThen' function can be used to create distributions
+      --   that result from first taking a value from a distribution,
+      --   and then, depending on that value, returning a new distribution.
+      --
+      --   >>> uniform [1 .. 2] `andThen` (\ n -> uniform [-n .. n])
+      --   fromList [(-2,1 % 10),(-1,4 % 15),(0,4 % 15),(1,4 % 15),(2,1 % 10)]
+
+      -- *** Numeric distributions
+
+      -- | Distributions over numeric values can also be combined using
+      --   addition, substraction, multiplication and division.
+      --
+      --   >>> uniform [1 .. 4] + uniform [1 .. 2]
+      --   fromList [(2,1 % 8),(3,1 % 4),(4,1 % 4),(5,1 % 4),(6,1 % 8)]
+      --   >>> uniform [1 .. 4] * uniform [0 .. 1]
+      --   fromList [(0,1 % 2),(1,1 % 8),(2,1 % 8),(3,1 % 8),(4,1 % 8)]
+      --
+      --   For multiple experiments, the 'trials' and 'times' functions
+      --   can be used. @trials@ counts the number of successes from
+      --   @n@ random independant experiments.
+      --
+      --   >>> trials 4 $ uniform [True, False]
+      --   fromList [(0,1 % 16),(1,1 % 4),(2,3 % 8),(3,1 % 4),(4,1 % 16)]
+      --   >>> trials 2 $ withProbability 0.75
+      --   fromList [(0,1 % 16),(1,3 % 8),(2,9 % 16)]
+      --
+      --   On the other hand, 'times' sums the outcome of @n@
+      --   independant experiments.
+      --
+      --   >>> times 2 $ uniform [1, 2, 3]
+      --   fromList [(2,1 % 9),(3,2 % 9),(4,1 % 3),(5,2 % 9),(6,1 % 9)]
+      --
+      --   Note the difference between @*@ and 'times'.
+      --
+      --   >>> times 2 $ uniform [1 .. 2]
+      --   fromList [(2,1 % 4),(3,1 % 2),(4,1 % 4)]
+      --   >>> 2 * uniform [1 .. 2]
+      --   fromList [(2,1 % 2),(4,1 % 2)]
+
+      -- ** Sampling
+
+      -- | To get random values from distributions, we must first create
+      --   a generator. For this, the 'fromDistribution' function is used.
+      --   Once we have a generator, we can get random values using the
+      --   'sample' or 'getSample' functions. 'sample' takes a generator
+      --   and a 'StdGen' from "System.Random" and returns a random value
+      --   from the distribution and a new 'StdGen'.
+      --
+      --   >>> let g = fromDistribution $ trials 10 $ withProbability 0.75
+      --   >>> fst $ sample g $ mkStdGen 12345
+      --   7
+      --   >>> fst $ sample g $ mkStdGen 67890
+      --   9
+      --
+      --   On the other hand, 'getSample' does the same, but directly in a
+      --   'MonadRandom' from "Control.Monad.Random".
+      --   (See "Data.Distribution.Sample" for more details)
+
+      -- ** Plotting
+
+      -- | Have a look at the "Data.Distribution.Plot" module made available
+      --   by the @distribution-plot@ package if you are interested
+      --   in plotting distributions to files.
+    ) where
+
+import System.Random (mkStdGen)  -- For doctest.
+
+import Data.Distribution.Core
+import Data.Distribution.Measure
+import Data.Distribution.Aggregator
+import Data.Distribution.Sample
diff --git a/Data/Distribution/Aggregator.hs b/Data/Distribution/Aggregator.hs
new file mode 100644
--- /dev/null
+++ b/Data/Distribution/Aggregator.hs
@@ -0,0 +1,107 @@
+{- Copyright 2014 Romain Edelmann
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License. -}
+
+
+-- | Module containing functions to apply on
+--   lists of values tagged with their probability,
+--   in order to somehow aggregate or transform the
+--   probabilities.
+module Data.Distribution.Aggregator
+    ( -- * Aggregation
+      Aggregator
+      -- ** Creation
+    , makeAggregator
+    , makePureAggregator
+    , separated
+      -- ** Application
+    , modifyProbabilities
+    , aggregateWith
+      -- ** Useful aggregators
+    , cumulative
+    , decreasing
+    , complementary
+    ) where
+
+import Data.Monoid
+
+import Data.Distribution.Core
+
+
+-- Aggregation
+
+
+-- | Functions that can modify probabilities.
+newtype Aggregator a = Aggregator
+    { modifyProbabilities :: [(a, Probability)] -> [Probability]
+      -- ^ Applies the aggregator and returns the modified list
+      --   of probabilities.
+    }
+
+-- | 'mempty' is the aggregator that leaves probabilities untouched,
+--   and 'mappend' compose aggregators.
+instance Monoid (Aggregator a) where
+    mempty = Aggregator (map snd)
+    mappend (Aggregator f) g = Aggregator (f . aggregateWith g)
+
+-- | Applies an aggregator on a list of values tagged with their probability.
+--   The values themselves are left unchanged.
+aggregateWith :: Aggregator a -> [(a, Probability)] -> [(a, Probability)]
+aggregateWith (Aggregator f) xs = zip vs $ f xs
+  where
+    vs = map fst xs
+
+-- | Creates an aggregator from a function ignoring the values.
+--   The function should not modify the number of elements.
+makePureAggregator :: ([Probability] -> [Probability]) -> Aggregator a
+makePureAggregator f = Aggregator $ f . map snd
+
+-- | Creates an aggregator from a function.
+--   The function should not modify the number of elements.
+makeAggregator :: ([(a, Probability)] -> [Probability]) -> Aggregator a
+makeAggregator = Aggregator
+
+-- | Aggregator that applies the first aggregator on values less than @x@
+--   and the second on values greater than @x@. Potential probability at @x@
+--   is left untouched.
+separated :: Ord a => a -> Aggregator a -> Aggregator a -> Aggregator a
+separated x la ga = makeAggregator go
+  where
+    go xs = mconcat
+        [ modifyProbabilities la ls
+        , modifyProbabilities mempty es
+        , modifyProbabilities ga gs ]
+      where
+        (ls, egs) = span ((< x) . fst) xs
+        (es, gs) = span ((== x) . fst) egs
+
+-- | Adds to each probability the sum of the probabilities earlier in the list.
+--
+--   >>> aggregateWith cumulative $ toList $ uniform [1 .. 5]
+--   [(1,1 % 5),(2,2 % 5),(3,3 % 5),(4,4 % 5),(5,1 % 1)]
+cumulative :: Aggregator a
+cumulative = makePureAggregator (scanl1 (+))
+
+-- | Replaces each probability by its complement.
+--
+--   >>> aggregateWith complementary $ toList $ uniform [1 .. 5]
+--   [(1,4 % 5),(2,4 % 5),(3,4 % 5),(4,4 % 5),(5,4 % 5)]
+complementary :: Aggregator a
+complementary = makePureAggregator (map (1 -))
+
+-- | Adds to each probability the sum of probabilities later in the list.
+--
+--   >>> aggregateWith decreasing  $ toList $ uniform [1 .. 5]
+--   [(1,1 % 1),(2,4 % 5),(3,3 % 5),(4,2 % 5),(5,1 % 5)]
+decreasing :: Aggregator a
+decreasing = makePureAggregator (scanr1 (+))
diff --git a/Data/Distribution/Core.hs b/Data/Distribution/Core.hs
new file mode 100644
--- /dev/null
+++ b/Data/Distribution/Core.hs
@@ -0,0 +1,388 @@
+{-# LANGUAGE MultiWayIf #-}
+
+{- Copyright 2014 Romain Edelmann
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License. -}
+
+
+-- | This modules defines types and functions for manipulating
+--   finite discrete probability distributions.
+module Data.Distribution.Core
+    ( -- * Probability
+      Probability
+      -- * Distribution
+    , Distribution
+    , toMap
+    , toList
+      -- ** Properties
+    , size
+    , support
+      -- ** Creation
+    , fromList
+    , always
+    , uniform
+    , withProbability
+      -- ** Transformation
+    , select
+    , assuming
+      -- ** Combination
+    , combine
+      -- ** Sequences
+      -- *** Independant experiments
+    , trials
+    , times
+      -- *** Dependant experiments
+    , andThen
+    , on
+    ) where
+
+import Control.Arrow (second)
+import qualified Data.Function as F
+import Data.List (tails, groupBy, sortBy, find)
+import Data.Map (Map)
+import qualified Data.Map as Map
+import Data.Maybe (fromMaybe)
+import Data.Monoid
+import Data.Ord (comparing)
+import Data.Set (Set)
+
+
+-- | Probability. Should be between 0 and 1.
+type Probability = Rational
+
+-- | Distribution over values of type @a@.
+--
+--   Due to their internal representations, @Distribution@ can not have
+--   @Functor@ or @Monad@ instances.
+--   However, 'select' is the equivalent of @fmap@ for distributions
+--   and 'always' and 'andThen' are respectively the equivalent of @return@
+--   and @>>=@.
+newtype Distribution a = Distribution
+    { toMap :: Map a Probability
+      -- ^ Converts the distribution to a mapping from values to their
+      --   probability. Values with probability @0@ are not included
+      --   in the resulting mapping.
+    } deriving Eq
+
+instance Show a => Show (Distribution a) where
+    show d = "fromList " ++ show (toList d)
+
+-- | A distribution @d1@ is less than some other distribution @d2@
+--   if the smallest value that has a different probability
+--   in @d1@ and @d2@ is more probable in @d1@.
+--
+--   By convention, empty distributions are less than
+--   everything except themselves.
+instance Ord a => Ord (Distribution a) where
+    compare d1 d2 = case (toList d1, toList d2) of
+        ([], []) -> EQ
+        ([], _)  -> LT
+        (_, [])  -> GT
+        (xs, ys) -> case find (uncurry (/=)) $ zip xs ys of
+            Nothing -> EQ
+            Just ((x, p), (y, q)) -> case compare x y of
+                EQ -> compare q p
+                c  -> c
+
+-- | Lifts the bounds to the distributions that return them
+--   with probability one.
+--
+--   Note that the degenerate distributions of size @0@ will
+--   be less than the distribution @minBound@.
+--
+--   Appart from that, all other distributions d have
+--   the property that @minBound <= d <= maxBound@ if
+--   this property holds on the values of the distribution.
+instance Bounded a => Bounded (Distribution a) where
+    minBound = always minBound
+    maxBound = always maxBound
+
+-- | Literals are interpreted as distributions that always
+--   return the given value.
+--
+--   >>> 42 == always 42
+--   True
+--
+--   Binary operations on distributions are defined to
+--   be the binary operation on each pair of elements.
+--
+--   For this reason, @(+)@ and @(*)@ are not related in the same way
+--   as they are on natural numbers.
+--
+--   For instance, it is not always the case that:
+--   @3 * d == d + d + d@
+--
+--   >>> let d = uniform [0, 1]
+--   >>> 3 * d
+--   fromList [(0,1 % 2),(3,1 % 2)]
+--   >>> d + d + d
+--   fromList [(0,1 % 8),(1,3 % 8),(2,3 % 8),(3,1 % 8)]
+--
+--   For this particular behavior, see the `times` function.
+instance (Ord a, Num a) => Num (Distribution a) where
+    fromInteger = always . fromInteger
+    abs = select abs
+    signum = select signum
+    negate = select negate
+    d1 + d2 = d1 `andThen` (+) `on` d2
+    d1 - d2 = d1 `andThen` (-) `on` d2
+    d1 * d2 = d1 `andThen` (*) `on` d2
+
+-- Binary operations on distributions are defined to
+-- be the binary operation on each pair of elements.
+instance (Ord a, Fractional a) => Fractional (Distribution a) where
+    fromRational = always . fromRational
+    d1 / d2 = d1 `andThen` (/) `on` d2
+    recip = select recip
+
+-- Binary operations on distributions are defined to
+-- be the binary operation on each pair of element.
+instance (Ord a, Floating a) => Floating (Distribution a) where
+    pi = always pi
+    exp = select exp
+    sqrt = select sqrt
+    log = select log
+    d1 ** d2 = d1 `andThen` (**) `on` d2
+    d1 `logBase` d2 = d1 `andThen` logBase `on` d2
+    sin = select sin
+    tan = select tan
+    cos = select cos
+    asin = select asin
+    atan = select atan
+    acos = select acos
+    sinh = select sinh
+    tanh = select tanh
+    cosh = select cosh
+    asinh = select asinh
+    atanh = select atanh
+    acosh = select acosh
+
+instance (Ord a, Monoid a) => Monoid (Distribution a) where
+    mempty = always mempty
+    mappend d1 d2 = d1 `andThen` mappend `on` d2
+
+-- | Converts the distribution to a list of increasing values whose probability
+--   is greater than @0@. To each value is associated its probability.
+toList :: Distribution a -> [(a, Probability)]
+toList (Distribution xs) = Map.toAscList xs
+
+
+-- Properties
+
+
+-- | Returns the number of elements with non-zero probability
+--   in the distribution.
+size :: Distribution a -> Int
+size = Map.size . toMap
+
+-- | Values in the distribution with non-zero probability.
+support :: Distribution a -> Set a
+support = Map.keysSet . toMap
+
+
+-- Creation
+
+
+-- | Distribution that assigns to each @value@ from the given @(value, weight)@
+--   pairs a probability proportional to @weight@.
+--
+--   >>> fromList [('A', 1), ('B', 2), ('C', 1)]
+--   fromList [('A',1 % 4),('B',1 % 2),('C',1 % 4)]
+--
+--   Values may appear multiple times in the list. In this case, their total
+--   weight is the sum of the different associated weights.
+--   Values whose total weight is zero or negative are ignored.
+fromList :: (Ord a, Real p) => [(a, p)] -> Distribution a
+fromList xs = Distribution $ Map.fromDistinctAscList $ zip vs scaledPs
+  where
+    as = map aggregate $ groupBy ((==) `F.on` fst) $ sortBy (comparing fst) xs
+      where
+        aggregate ys = let (v : _, qs) = unzip ys in
+            (v, fromRational $ toRational $ sum qs)
+    (vs, ps) = unzip $ filter ((> 0) . snd) as
+    t = sum ps
+    scaledPs = if t /= 1 then map (/ t) ps else ps
+
+-- | Distribution that assigns to @x@ the probability of @1@.
+--
+-- >>> always 0
+-- fromList [(0,1 % 1)]
+--
+-- >>> always 42
+-- fromList [(42,1 % 1)]
+always :: a -> Distribution a
+always x = Distribution $ Map.singleton x 1
+
+-- | Uniform distribution over the values.
+--   The probability of each element is proportional
+--   to its number of appearance in the list.
+--
+--   >>> uniform [1 .. 6]
+--   fromList [(1,1 % 6),(2,1 % 6),(3,1 % 6),(4,1 % 6),(5,1 % 6),(6,1 % 6)]
+uniform :: (Ord a) => [a] -> Distribution a
+uniform xs = fromList $ fmap (\ x -> (x, p)) xs
+  where
+    p = 1 / toRational (length xs)
+
+-- | @True@ with given probability and @False@ with complementary probability.
+withProbability :: Real p => p -> Distribution Bool
+withProbability p = fromList [(False, 1 - p'), (True, p')]
+  where
+    p' = fromRational $ max 0 $ min 1 $ toRational p
+
+
+-- Transformation
+
+
+-- | Applies a function to the values in the distribution.
+--
+--   >>> select abs $ uniform [-1, 0, 1]
+--   fromList [(0,1 % 3),(1,2 % 3)]
+select :: Ord b => (a -> b) -> Distribution a -> Distribution b
+select f (Distribution xs) = Distribution $ Map.mapKeysWith (+) f xs
+
+-- | Returns a new distribution conditioning on the predicate holding
+--   on the value.
+--
+--   >>> assuming (> 2) $ uniform [1 .. 6]
+--   fromList [(3,1 % 4),(4,1 % 4),(5,1 % 4),(6,1 % 4)]
+--
+--   Note that the resulting distribution will be empty
+--   if the predicate does not hold on any of the values.
+--
+--   >>> assuming (> 7) $ uniform [1 .. 6]
+--   fromList []
+assuming :: (a -> Bool) -> Distribution a -> Distribution a
+assuming f (Distribution xs) = Distribution $ fmap adjust filtered
+  where
+    filtered = Map.filterWithKey (const . f) xs
+    adjust x = x * (1 / total)
+    total = sum $ Map.elems filtered
+
+
+-- Combination
+
+
+-- | Combines multiple weighted distributions into a single distribution.
+--
+--   The probability of each element is the weighted sum of the element's
+--   probability in every distribution.
+--
+--   >>> combine [(always 2, 1 / 3), (uniform [1..6], 2 / 3)]
+--   fromList [(1,1 % 9),(2,4 % 9),(3,1 % 9),(4,1 % 9),(5,1 % 9),(6,1 % 9)]
+--
+--   Note that the weights do not have to sum up to @1@. Distributions with
+--   negative or null weight will be ignored.
+combine :: (Ord a, Real p) => [(Distribution a, p)] -> Distribution a
+combine dws = Distribution $ Map.unionsWith (+) $ zipWith go ds ps
+  where
+    (ds, ws) = unzip $ filter ((> 0) . snd) $ map (second toRational) dws
+    w = sum ws
+    ps = map (/ w) ws
+    go (Distribution xs) p = fmap (* p) xs
+
+
+-- Sequences
+
+
+-- | Binomial distribution.
+--   Assigns to each number of successes its probability.
+--
+--   >>> trials 2 $ uniform [True, False]
+--   fromList [(0,1 % 4),(1,1 % 2),(2,1 % 4)]
+trials :: Int -> Distribution Bool -> Distribution Int
+trials n d = Distribution $ Map.fromDistinctAscList $ if
+    | p == 1    -> [(n, 1)]
+    | p == 0    -> [(0, 1)]
+    | otherwise -> zip outcomes probs
+  where
+    p = fromMaybe 0 $ Map.lookup True $ toMap d
+    q = 1 - p
+
+    ps = take (n + 1) $ iterate (* p) 1
+    qs = reverse $ take (n + 1) $ iterate (* q) 1
+
+    probs = zipWith (*) pascalRow $ zipWith (*) ps qs
+
+    outcomes = [0 .. n]
+
+    pascalRow = fmap (fromRational . toRational) $
+        scanl ( \ c k -> c * (n' + 1 - k) `div` k) 1 [1 .. n']
+      where
+        n' = toInteger n
+
+-- | Takes `n` samples from the distribution and returns the distribution
+--   of their sum.
+--
+--   >>> times 2 $ uniform [1 .. 3]
+--   fromList [(2,1 % 9),(3,2 % 9),(4,1 % 3),(5,2 % 9),(6,1 % 9)]
+--
+--   This function makes use of the more efficient @trials@ functions
+--   for input distributions of size @2@.
+--
+--   >>> size $ times 10000 $ uniform [1, 10]
+--   10001
+times :: (Num a, Ord a) => Int -> Distribution a -> Distribution a
+n `times` d
+    | s == 0 = d
+    | n <= 0 = always 0
+    | s == 1 = select (* n') d
+    | s == 2 = case toList d of  -- Performs Bernoulli trials. (efficiency)
+        [(a, p), (b, q)] -> select (go a b) $ trials n $ withProbability p
+        _ -> error "times: size seems not to be properly defined."
+    | otherwise = mult n
+  where
+    s = Map.size $ toMap d
+    n' = fromInteger $ toInteger n
+    go a b k = k' * a + (n' - k') * b
+      where
+        k' = fromInteger $ toInteger k
+
+    -- Computes @k `times` d@ using a divide and conquer approach.
+    mult 1 = d
+    mult k = if r == 0 then twice d' else twice d' + d
+      where
+        d' = mult k'
+        (k', r) = k `quotRem` 2
+
+    -- Computes @d + d@ more efficiently.
+    twice (Distribution xs) = Distribution $ Map.unionsWith (+) $ do
+        (x, p) : ys <- init $ tails $ Map.toAscList xs
+        return $ Map.fromDistinctAscList $ (:) (x + x, p * p) $ do
+            (y, q) <- ys
+            let p' = 2 * p * q
+            return (y + x, p')
+
+-- | Computes for each value in the distribution a new distribution, and then
+--   combines those distributions, giving each the weight of the original value.
+--
+--   >>> uniform [1 .. 3] `andThen` (\ n -> uniform [1 .. n])
+--   fromList [(1,11 % 18),(2,5 % 18),(3,1 % 9)]
+--
+--   See the 'on' function for a convenient way to chain distributions.
+infixl 7 `andThen`
+andThen :: Ord b => Distribution a -> (a -> Distribution b) -> Distribution b
+andThen (Distribution xs) f = Distribution $
+    Map.unionsWith (+) $ fmap go $ Map.toList xs
+  where
+    go (x, p) = fmap (* p) $ toMap $ f x
+
+-- | Utility to partially apply a function on a distribution.
+--   A use case for 'on' is to use it in conjunction with 'andThen'
+--   to combine distributions.
+--
+--   >>> uniform [1 .. 3] `andThen` (+) `on` uniform [1 .. 2]
+--   fromList [(2,1 % 6),(3,1 % 3),(4,1 % 3),(5,1 % 6)]
+infixl 8 `on`
+on :: Ord c => (a -> b -> c) -> Distribution b -> a -> Distribution c
+on f d x = select (f x) d
diff --git a/Data/Distribution/Domain/Coin.hs b/Data/Distribution/Domain/Coin.hs
new file mode 100644
--- /dev/null
+++ b/Data/Distribution/Domain/Coin.hs
@@ -0,0 +1,46 @@
+{- Copyright 2014 Romain Edelmann
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License. -}
+
+-- | This modules provides distributions from coins and
+--   functions on coins.
+module Data.Distribution.Domain.Coin
+    ( -- * Coin
+      Coin
+    , CoinSide (..)
+    , coin
+      -- ** Operations
+    , flipsOf
+    , reflipOn
+    ) where
+
+import Data.Distribution.Core
+
+-- | Distribution over the sides of a coin.
+type Coin = Distribution CoinSide
+
+-- | Possible outcomes of a coin flip.
+data CoinSide = Head | Tail
+  deriving (Eq, Ord, Show, Read, Enum)
+
+-- | Fair coin.
+coin :: Coin
+coin = uniform [Head, Tail]
+
+-- | Flips `n` times the given coin and counts the number of heads.
+flipsOf :: Int -> Coin -> Distribution Int
+n `flipsOf` d = n `trials` select (== Head) d
+
+-- | Rerolls the coin once if the first outcome satifies the given predicate.
+reflipOn :: CoinSide -> Coin -> Coin
+reflipOn s d = d `andThen` \ r -> if r == s then d else always r
diff --git a/Data/Distribution/Domain/Dice.hs b/Data/Distribution/Domain/Dice.hs
new file mode 100644
--- /dev/null
+++ b/Data/Distribution/Domain/Dice.hs
@@ -0,0 +1,72 @@
+{- Copyright 2014 Romain Edelmann
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License. -}
+
+
+-- | This modules provides distributions from dice and
+--   functions on dice.
+module Data.Distribution.Domain.Dice
+    ( -- * Dice
+      Dice
+    , dice
+      -- ** Common dice
+    , d4
+    , d6
+    , d8
+    , d10
+    , d20
+      -- ** Operations
+    , rollsOf
+    , rerollOn
+    ) where
+
+import Data.Distribution.Core
+
+-- | Distribution of the result of dice rolls.
+type Dice = Distribution Int
+
+-- | Fair dice of @n@ faces.
+dice :: Int -> Dice
+dice n = uniform [1 .. n]
+
+-- | Fair dice of @4@ faces.
+d4 :: Dice
+d4 = dice 4
+
+-- | Fair dice of @6@ faces.
+d6 :: Dice
+d6 = dice 6
+
+-- | Fair dice of @8@ faces.
+d8 :: Dice
+d8 = dice 8
+
+-- | Fair dice of @10@ faces.
+d10 :: Dice
+d10 = dice 10
+
+-- | Fair dice of @12@ faces.
+d12 :: Dice
+d12 = dice 12
+
+-- | Fair dice of @20@ faces.
+d20 :: Dice
+d20 = dice 20
+
+-- | Rolls `n` times the given dice and sums the results.
+rollsOf :: Int -> Dice -> Dice
+n `rollsOf` d = n `times` d
+
+-- | Rerolls the dice once if the first outcome satifies the given predicate.
+rerollOn :: (Int -> Bool) -> Dice -> Dice
+rerollOn f d = d `andThen` \ n -> if f n then d else always n
diff --git a/Data/Distribution/Measure.hs b/Data/Distribution/Measure.hs
new file mode 100644
--- /dev/null
+++ b/Data/Distribution/Measure.hs
@@ -0,0 +1,153 @@
+{- Copyright 2014 Romain Edelmann
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License. -}
+
+
+-- | This modules provides various measures on
+--   finite discrete probability distributions.
+module Data.Distribution.Measure
+    ( -- * Probability
+      probability
+    , probabilityAt
+    , probabilityIn
+      -- * Expectation
+    , expectation
+    , mean
+      -- * Variation
+    , variance
+    , standardDeviation
+      -- * Values
+    , median
+    , modes
+    , quantile
+    ) where
+
+import Control.Arrow (second)
+import qualified Data.Map as Map
+import Data.Maybe (fromMaybe)
+
+import Data.Distribution.Core
+
+
+-- | Probability that a predicate holds on the distribution.
+--
+--   >>> probability (\ x -> x == 1 || x == 6) $ uniform [1 .. 6]
+--   1 % 3
+--
+--   Takes @O(n)@ time. See 'probabilityAt' and 'probabilityIn'
+--   for a more efficient ways to query elements and ranges.
+probability :: (a -> Bool) -> Distribution a -> Probability
+probability f = sum . Map.elems . Map.filterWithKey (const . f) . toMap
+
+-- | Probability of a given value.
+--
+--   Takes @O(log(n))@ time.
+probabilityAt :: Ord a => a -> Distribution a -> Probability
+probabilityAt x = fromMaybe 0 . Map.lookup x . toMap
+
+-- | Probability of a the inclusive @[low, high]@ range.
+--   When @low > high@, the probability is 0.
+--
+--   Takes @O(log(n) + m)@ time, where @n@ is the size of
+--   the distribution and @m@ the size of the range.
+probabilityIn :: Ord a => (a, a) -> Distribution a -> Probability
+probabilityIn (low, high) d
+    | low > high = 0
+    | low == high = probabilityAt low d
+    | otherwise = Map.foldl' (+) (ph + pl) ps
+  where
+    (_, ml, hs) = Map.splitLookup low $ toMap d
+    (ps, mh, _) = Map.splitLookup high hs
+
+    pl = fromMaybe 0 ml
+    ph = fromMaybe 0 mh
+
+-- | Returns the expectation, or mean, of a distribution.
+--
+-- >>> expectation $ uniform [0, 1]
+-- 0.5
+--
+-- Empty distributions have an expectation of @0@.
+expectation :: (Real a, Fractional b) => Distribution a -> b
+expectation = fromRational . sum .
+    fmap (uncurry (*) . second toRational) .
+    Map.toList . Map.mapKeysWith (+) toRational . toMap
+
+-- | Returns the variance of a distribution.
+--
+-- >>> variance $ always 1
+-- 0.0
+-- >>> variance $ uniform [0 .. 1]
+-- 0.25
+-- >>> variance $ uniform [1 .. 7]
+-- 4.0
+--
+-- Empty distributions have a variance of @0@.
+variance :: (Real a, Fractional b) => Distribution a -> b
+variance d = expectation dSquare - (e * e)
+  where
+    e = expectation d
+    dSquare = select (square . toRational) d
+    square x = x * x
+
+-- | Standard deviation.
+--
+--   >>> standardDeviation $ always 1
+--   0.0
+--   >>> standardDeviation $ uniform [0 .. 1]
+--   0.5
+--   >>> standardDeviation $ uniform [1 .. 7]
+--   2.0
+standardDeviation :: (Real a, Floating b) => Distribution a -> b
+standardDeviation = sqrt . fromRational . variance
+
+-- | Returns the smallest value in the distribution such that
+--   at least a fraction `p` of the values are less or equal to it.
+--
+--   >>> quantile 0.0 $ uniform [1, 2, 3]
+--   Just 1
+--   >>> quantile 0.5 $ uniform [1, 2, 3]
+--   Just 2
+--   >>> quantile 1.0 $ uniform [1, 2, 3]
+--   Just 3
+--   >>> quantile 0.5 $ fromList []
+--   Nothing
+quantile :: Probability -> Distribution a -> Maybe a
+quantile p d = case dropWhile ((< r) . snd) $ scanl1 go $ toList d of
+    (x, _) : _ -> Just x
+    _          -> Nothing
+  where
+    r = max 0 $ min 1 p
+    go (_, q') (x, q) = (x, q' + q)
+
+-- | Returns the median of the values.
+--   The median is the smallest value such that at least 50% of
+--   the values are less or equal to it.
+--
+--   >>> median $ fromList [(1, 0.6), (2, 0.4)]
+--   Just 1
+--   >>> median $ fromList [(1, 0.4), (2, 0.6)]
+--   Just 2
+median :: Distribution a -> Maybe a
+median = quantile 0.5
+
+-- | Synonym of 'expectation'.
+mean :: (Real a, Fractional b) => Distribution a -> b
+mean = expectation
+
+-- | Returns all values whose probability is maximal.
+modes :: Distribution a -> [a]
+modes d = map fst $ filter ((m ==) . snd) xs
+  where
+    xs = toList d
+    m = maximum $ map snd xs
diff --git a/Data/Distribution/Sample.hs b/Data/Distribution/Sample.hs
new file mode 100644
--- /dev/null
+++ b/Data/Distribution/Sample.hs
@@ -0,0 +1,196 @@
+{-# LANGUAGE MultiWayIf #-}
+
+{- Copyright 2014 Romain Edelmann
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License. -}
+
+
+-- | This modules provides ways to randomly and efficiently sample values
+--   from distributions.
+--
+--   Walker's <http://en.wikipedia.org/wiki/Alias_method alias method> is
+--   used internally, so that values can be sampled in constant time.
+module Data.Distribution.Sample
+    ( -- * Generator
+      Generator
+      -- ** Building
+    , fromDistribution
+    , safeFromDistribution
+      -- ** Sampling
+    , sample
+    , getSample
+    ) where
+
+import Control.Monad.Random.Class (MonadRandom, getRandom, getRandomR)
+import Control.Monad.ST.Safe
+import Data.Array.IArray
+import Data.Array.MArray.Safe
+import Data.Array.Unboxed
+import Data.Array.ST.Safe
+import System.Random (RandomGen, random, randomR)
+
+import Data.Distribution.Core
+
+-- | Generator of random values of type @a@.
+--
+--   Can be created in linear time from distributions
+--   and sampled in constant time.
+data Generator a = Generator
+    { capacity :: !Int
+      -- ^ Number of buckets.
+    , probabilities :: !(UArray Int Double)
+      -- ^ Probability to stay in the bucket.
+    , values :: !(Array Int a)
+      -- ^ Value in the bucket.
+    , indexes :: !(UArray Int Int)
+      -- ^ Index of the "guest" value. Used when the bucket is left.
+    }
+
+instance Functor Generator where
+    fmap f (Generator n ps vs is) = Generator n ps (fmap f vs) is
+
+-- | Creates a generator from the given non-empty distribution.
+--
+--   Runs in @O(n)@ time where @n@ is the size of the distribution.
+fromDistribution :: Distribution a -> Generator a
+fromDistribution d = case toList d of
+    [] -> error "makeGenerator: Undefined on empty distributions."
+    xs -> generate xs
+  where
+    n = size d
+
+    -- Creates the generator using Walker's algorithm.
+    --
+    -- The main idea is to put each value into its own bucket.
+    -- In addition, each bucket has a probability to be discarded when picked,
+    -- in which case another value, the "guest" of the bucket,
+    -- is chosen instead.
+    --
+    -- The following procedure sets the probabilities and guests of
+    -- the bucket so that the probability to choose the value of a bucket
+    -- is the probability of the value in the input distribution.
+    generate xs = runST $ do
+        -- The values are directly from the list.
+        let vs = listArray (0, n - 1) as
+
+        -- The probability to stay in the bucket is @n@ times the
+        -- probability in the distribution. This is due to the fact
+        -- that each of the @n@ buckets is chosen with probability @1 / n@.
+        -- Note that this can well exceed @1@. This will be taken care
+        -- during the equilibration phase.
+        -- In case the value exceed @1@, the bucket is said to be overfilled,
+        -- and if its is strictly less than @1@, underfilled.
+        ps <- stArrayFromList sqs
+
+        -- The indexes of "guest" values.
+        -- The correct indexes will be set during the equilibration phase.
+        -- Guest values are used by underfilled buckets.
+        is <- stuArray 0
+
+        -- The 'go' function is used to equilibrate the buckets, by assigning
+        -- unused space in underfilled buckets to overfilled buckets.
+        --
+        -- As first argument are the indexes which have a probability > 1
+        -- (indexes of overfilled buckets),
+        -- and as second argument those which have a probability < 1
+        -- (indexed of underfilled buckets)
+        --
+        -- The idea behind the function is to take an overfilled and an
+        -- underfilled bucket, and to completely "fill" the underfilled bucket.
+        -- To do so, the overfilled bucket is registered as the guest of the
+        -- underfilled bucket. The probability of the overfilled bucket is
+        -- then reduced by the amount that was "poured" into the underfilled
+        -- bucket.
+        let go (o : os) (u : us) = do
+                -- First, we register o as the guest of u.
+                writeArray is u o
+
+                -- We then update the probability of o.
+                po <- readArray ps o
+                pu <- readArray ps u
+                let po' = po - (1 - pu)
+                writeArray ps o po'
+
+                -- We recurse on the new overfilled and underfilled buckets.
+                if | po' < 1 -> go os (o : us)  -- We took too much from o.
+                   | po' == 1 -> go os us       -- o perfectly fits its bucket.
+                   | otherwise -> go (o : os) us  -- o is still too large.
+
+            go [] [] = return ()  -- All buckets are filled.
+            go _ _ = error "makeGenerator: Implementation error."
+
+        -- We select the initial overfilled and underfilled buckets.
+        let os = map fst $ filter ((> 1) . snd) iqs
+            us = map fst $ filter ((< 1) . snd) iqs
+
+        -- We perform the equilibration phase.
+        go os us
+
+        -- Each bucket is now completely filled. We freeze the result.
+        fps <- freeze ps
+        fis <- freeze is
+        return $ Generator
+            n
+            (listArray (0, n - 1)
+                (fmap fromRational $ elems (fps :: Array Int Rational)))
+            vs
+            fis
+      where
+        -- Separating the values from their probability.
+        (as, qs) = unzip xs
+
+        -- Scaling the probabilities by @n@. This is due to the fact that each
+        -- of the @n@ buckets is uniformly chosen with probability @1 / n@.
+        sqs = map (* fromIntegral n) qs
+
+        -- Indexed and scaled probabilities.
+        iqs = zip [0 ..] sqs
+
+    stArrayFromList :: [e] -> ST s (STArray s Int e)
+    stArrayFromList = newListArray (0, n - 1)
+
+    stuArray :: e -> ST s (STArray s Int e)
+    stuArray = newArray (0, n - 1)
+
+-- | Safe version of 'fromDistribution'. Returns @Nothing@ when the
+--   given distribution is empty.
+safeFromDistribution :: Distribution a -> Maybe (Generator a)
+safeFromDistribution d = if size d == 0
+    then Nothing
+    else Just $ fromDistribution d
+
+-- | Picks a random value from the generator.
+--
+--   Runs in constant @O(1)@ time.
+getSample :: MonadRandom m => Generator a -> m a
+getSample g = do
+    let n = capacity g
+    u <- getRandom
+    j <- getRandomR (0, n - 1)
+    let i = if u < probabilities g ! j
+                then j
+                else indexes g ! j
+    return $ values g ! i
+
+-- | Picks a random value from the generator.
+--
+--   Runs in constant @O(1)@ time.
+sample :: RandomGen g => Generator a -> g -> (a, g)
+sample g k = (values g ! i, k'')
+  where
+    n = capacity g
+    (j, k') = randomR (0, n - 1) k
+    (u, k'') = random k'
+    i = if u < probabilities g ! j
+            then j
+            else indexes g ! j
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/distribution.cabal b/distribution.cabal
new file mode 100644
--- /dev/null
+++ b/distribution.cabal
@@ -0,0 +1,65 @@
+
+-- The name of the package.
+name:                distribution
+
+-- The package version.  See the Haskell package versioning policy (PVP)
+-- for standards guiding when and how versions should be incremented.
+-- http://www.haskell.org/haskellwiki/Package_versioning_policy
+-- PVP summary:      +-+------- breaking API changes
+--                   | | +----- non-breaking API additions
+--                   | | | +--- code changes with no API change
+version:             1.0.0.0
+
+-- A short (one-line) description of the package.
+synopsis:             Finite discrete probability distributions.
+
+-- A longer description of the package.
+description:          Package for manipulating finite discrete probability distributions. Supports transformations, measurements, efficient sampling and plotting.
+
+-- URL for the project homepage or repository.
+homepage:            https://github.com/redelmann/haskell-distribution
+
+-- The license under which the package is released.
+license:             Apache-2.0
+
+-- The file containing the license text.
+license-file:        LICENSE
+
+-- The package author(s).
+author:              Romain Edelmann
+
+-- An email address to which users can send suggestions, bug reports, and
+-- patches.
+maintainer:          romain.edelmann@gmail.com
+
+-- A copyright notice.
+copyright:           Copyright 2014 Romain Edelmann
+
+category:            Math
+
+build-type:          Simple
+
+-- Constraint on the version of Cabal needed to build this package.
+cabal-version:       >=1.8
+
+
+library
+  -- Modules exported by the library.
+  exposed-modules:     Data.Distribution,
+                       Data.Distribution.Aggregator,
+                       Data.Distribution.Core,
+                       Data.Distribution.Domain.Coin,
+                       Data.Distribution.Domain.Dice,
+                       Data.Distribution.Measure,
+                       Data.Distribution.Sample
+
+  -- Modules included in this library but not exported.
+  -- other-modules:
+
+  -- Other library packages from which modules are imported.
+  build-depends:       array >=0.4,
+                       base >=4.5 && <5,
+                       containers ==0.5.*,
+                       MonadRandom ==0.1.*,
+                       random ==1.0.*
+
