content: {-# LANGUAGE DerivingStrategies #-}
  {-# LANGUAGE FlexibleInstances #-}
  {-# LANGUAGE GeneralizedNewtypeDeriving #-}
  {-# LANGUAGE MultiParamTypeClasses #-}
  
  -- |
  -- Slower than Control.Monad.Bayes.Density.Free, so not used by default,
  -- but more elementary to understand. Just uses standard
  -- monad transformer techniques.
  module Control.Monad.Bayes.Density.State where
  
  import Control.Monad.Bayes.Class (MonadDistribution (random))
  import Control.Monad.State (MonadState (get, put), StateT, evalStateT)
  import Control.Monad.Writer
  
  newtype DensityT m a = DensityT {getDensityT :: WriterT [Double] (StateT [Double] m) a} deriving newtype (Functor, Applicative, Monad)
  
  instance MonadTrans DensityT where
    lift = DensityT . lift . lift
  
  instance (Monad m) => MonadState [Double] (DensityT m) where
    get = DensityT $ lift $ get
    put = DensityT . lift . put
  
  instance (Monad m) => MonadWriter [Double] (DensityT m) where
    tell = DensityT . tell
    listen = DensityT . listen . getDensityT
    pass = DensityT . pass . getDensityT
  
  instance (MonadDistribution m) => MonadDistribution (DensityT m) where
    random = do
      trace <- get
      x <- case trace of
        [] -> random
        r : xs -> put xs >> pure r
      tell [x]
      pure x
  
  runDensityT :: (Monad m) => DensityT m b -> [Double] -> m (b, [Double])
  runDensityT (DensityT m) = evalStateT (runWriterT m)
  