probability-dist
A Haskell library providing probability distributions and related probability functions.
The library is designed around a small, explicit public API. Discrete and continuous probability distributions are exposed through separate modules, allowing applications to depend only on the functionality they need.
Features
- Discrete probability distributions
- Continuous probability distributions
- Probability mass functions (PMF)
- Probability density functions (PDF)
- Cumulative distribution functions (CDF)
- Distribution-specific moments where implemented
- Numerically stable logarithmic calculations for combinatorial and special functions
- Explicit error handling through
Either
Requirements
- GHC 9.10.3 or compatible GHC version
- Cabal 3.16.1.0 or compatible Cabal version
base >= 4.20 && < 5
Installation
Clone the repository and build it with Cabal:
git clone <repository-url>
cd probability-dist
cabal build
Run the test suite with:
cabal test
The package can also be built as a source distribution:
cabal sdist
Public API
The library exposes two public modules.
Discrete distributions
import Probability.Discrete
This module contains the discrete probability distributions implemented by the package.
Current distributions include:
- Binomial
- Negative Binomial
- Geometric
- Multinomial
Continuous distributions
import Probability.Continuous
This module contains the continuous probability distributions implemented by the package.
Current distributions include:
- Normal
- Exponential
- Gamma
- Uniform
The modules are intentionally separated so that an application requiring only discrete or only continuous distributions does not need to import both APIs.
Basic Usage
Binomial distribution
The binomial PMF is exposed through binomialPMF.
import Probability.Discrete
main :: IO ()
main = do
print (binomialPMF 3 10 0.5)
The parameters are:
k n p
where:
k is the number of successes
n is the number of trials
p is the probability of success
The result is returned as an Either value, allowing invalid parameters to be handled explicitly.
For example:
binomialPMF 3 10 0.5
returns a Right value containing the probability.
An invalid success count produces an error:
binomialPMF 11 10 0.5
which returns a Left value.
Negative Binomial and Geometric Distributions
The geometric distribution is implemented as the special case of the negative binomial distribution where:
r = 1
For example:
import Probability.Discrete
main :: IO ()
main = do
print (negativeBinomialPMF 2 1 0.5)
print (geometricPMF 2 0.5)
The geometric distribution is therefore provided as a convenience function rather than requiring users to manually express it as a negative binomial distribution with r = 1.
Multinomial Distribution
The multinomial PMF accepts the total number of trials, a vector of category counts, and a corresponding probability vector.
import Probability.Discrete
main :: IO ()
main = do
print $
multinomialPMF
10
[4, 3, 3]
[0.4, 0.3, 0.3]
The count vector and probability vector must be dimensionally compatible.
Invalid input is represented through the package's error type rather than silently producing an invalid probability.
Normal Distribution
The normal distribution provides PDF and CDF functionality.
import Probability.Continuous
main :: IO ()
main = do
print (normalPDF 0.0 0.0 1.0)
print (normalCDF 0.0 0.0 1.0)
For the standard normal distribution:
μ = 0
σ = 1
the CDF at zero is:
0.5
The standard deviation is validated explicitly; non-positive values result in an error.
Exponential Distribution
The exponential distribution is parameterized by its rate λ.
import Probability.Continuous
main :: IO ()
main = do
print (exponentialPDF 1.0 2.0)
print (exponentialCDF 1.0 2.0)
The implementation uses numerically appropriate calculations for expressions such as:
1 - exp(-λx)
in order to improve numerical behavior for small values.
Gamma Distribution
The Gamma distribution is parameterized by shape and rate parameters.
import Probability.Continuous
main :: IO ()
main = do
print (gammaPDF 1.0 2.0 1.0)
print (gammaMean 2.0 1.0)
print (gammaVar 2.0 1.0)
The package also provides the corresponding mean and variance functions.
The exponential distribution can be viewed as a special case of the Gamma distribution with shape parameter equal to one.
The continuous uniform distribution is parameterized by its lower and upper bounds.
import Probability.Continuous
main :: IO ()
main = do
print (uniformPDF 0.5 0.0 1.0)
print (uniformCDF 0.5 0.0 1.0)
print (uniformMean 0.0 1.0)
print (uniformVar 0.0 1.0)
Invalid bounds are reported through the package's error handling mechanism.
Error Handling
Public distribution functions return results using Either.
This makes invalid statistical parameters explicit instead of relying on exceptions or silently returning meaningless numerical values.
For example:
case binomialPMF 11 10 0.5 of
Right probability ->
print probability
Left err ->
print err
The package defines distribution-related errors in its internal error module and exposes the resulting error values through the public functions.
Numerical Design
Several calculations involved in probability distributions can become numerically unstable when performed directly.
The package therefore uses logarithmic forms where appropriate, particularly for:
- factorial-related calculations
- combinations
- Gamma functions
- Beta functions
- probability expressions involving products of many terms
Internally, the package provides mathematical support functions such as:
logFactorial
logCombination
logGamma
logBeta
erf
These functions are implementation details and are kept outside the public API.
This separation allows the public distribution modules to remain focused on probability distributions while the numerical machinery remains internal to the package.
Testing
The project includes a Cabal test suite covering:
- ordinary distribution values
- boundary conditions
- invalid parameters
- probability constraints
- dimensional consistency
- numerical results
- degenerate cases
- error handling
Run all tests with:
cabal test
The package is also checked with:
cabal check
and can be packaged with:
cabal sdist
Project Structure
probability-dist/
├── src/
│ └── Probability/
│ ├── Continuous.hs
│ ├── Discrete.hs
│ ├── Error.hs
│ └── Math.hs
├── test/
│ └── Main.hs
├── LICENSE
├── README.md
├── probability-dist.cabal
└── CHANGELOG.md
Probability.Discrete and Probability.Continuous form the public API.
Probability.Math and Probability.Error are internal implementation modules.
License
This project is licensed under the BSD 3-Clause License.
See the LICENSE file for the complete license text.