{- |
Consider a family of two children.  Given that there is a boy in the family,
what is the probability that there are two boys in the family?
-}

module Numeric.Probability.Example.Boys where

import qualified Numeric.Probability.Distribution as Dist
import Numeric.Probability.Distribution ((??), (?=<<), )

import Control.Monad (liftM2, )


type Probability = Rational
type Dist a = Dist.T Probability a

data Child = Boy | Girl
             deriving (Eq,Ord,Show)

type Family = (Child, Child)

birth :: Dist Child
birth = Dist.uniform [Boy, Girl]

family :: Dist Family
family = liftM2 (,) birth birth

allBoys :: Dist.Event Family
allBoys (c0, c1) = (c0 == Boy && c1 == Boy)

existsBoy :: Dist.Event Family
existsBoy (c0, c1) = (c0 == Boy || c1 == Boy)

familyWithBoy :: Dist Family
familyWithBoy = existsBoy ?=<< family
{-
familyWithBoy =
   do f <- family
      guard (existsBoy f)
      return f
-}

twoBoys :: Probability
twoBoys = allBoys ?? familyWithBoy


countBoy :: Child -> Int
countBoy Boy = 1
countBoy Girl = 0

countBoys :: Family -> Int
countBoys (c0,c1) = countBoy c0 + countBoy c1

numBoys :: Dist Int
numBoys = Dist.map countBoys familyWithBoy