module Dice (diceHard, diceSoft) where

-- A toy model for dice rolling from http://dl.acm.org/citation.cfm?id=2804317
-- Exact results can be obtained using Dist monad

import Control.Applicative (Applicative (..))
import Control.Monad.Bayes.Class
  ( MonadDistribution (uniformD),
    MonadFactor (score),
    MonadMeasure,
    condition,
  )
-- Prelude exports liftA2 from GHC 9.6 on, see https://github.com/haskell/core-libraries-committee/blob/main/guides/export-lifta2-prelude.md
-- import Control.Applicative further up can be removed once we don't support GHC <= 9.4 anymore

import Prelude hiding (Applicative (..))

-- | A toss of a six-sided die.
die :: (MonadDistribution m) => m Int
die = uniformD [1 .. 6]

-- | A sum of outcomes of n independent tosses of six-sided dice.
dice :: (MonadDistribution m) => Int -> m Int
dice 1 = die
dice n = liftA2 (+) die (dice (n - 1))

-- | Toss of two dice where the output is greater than 4.
diceHard :: (MonadMeasure m) => m Int
diceHard = do
  result <- dice 2
  condition (result > 4)
  return result

-- | Toss of two dice with an artificial soft constraint.
diceSoft :: (MonadMeasure m) => m Int
diceSoft = do
  result <- dice 2
  score (1 / fromIntegral result)
  return result