{-# LANGUAGE TemplateHaskell #-}
module Polysemy.Random
  ( 
    Random (..)
    
  , random
  , randomR
    
  , runRandom
  , runRandomIO
  ) where
import           Polysemy
import           Polysemy.State
import qualified System.Random as R
data Random m a where
  Random :: R.Random x => Random m x
  RandomR :: R.Random x => (x, x) -> Random m x
makeSem ''Random
runRandom
    :: forall q r a
     . R.RandomGen q
    => q
    -> Sem (Random ': r) a
    -> Sem r (q, a)
runRandom q = runState q . reinterpret (\case
  Random -> do
    ~(a, q') <- gets @q R.random
    put q'
    pure a
  RandomR r -> do
    ~(a, q') <- gets @q $ R.randomR r
    put q'
    pure a
                                       )
{-# INLINE runRandom #-}
runRandomIO :: Member (Embed IO) r => Sem (Random ': r) a -> Sem r a
runRandomIO m = do
  q <- embed R.newStdGen
  snd <$> runRandom q m
{-# INLINE runRandomIO #-}