packages feed

moffy-samples-events-0.1.0.0: src/Control/Moffy/Samples/Event/Random/Internal.hs

{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE BlockArguments #-}
{-# LANGUAGE PatternSynonyms #-}
{-# LANGUAGE DataKinds, TypeOperators #-}
{-# LANGUAGE TypeFamilies #-}
{-# OPTIONS_GHC -Wall -fno-warn-tabs #-}

module Control.Moffy.Samples.Event.Random.Internal (
	-- * Store Random Gen
	StoreRandomGen(..), pattern OccStoreRandomGen,
	-- * Load Random Gen
	LoadRandomGen, pattern OccLoadRandomGen,
	-- * Get Random
	RandomEv, getRandom, getRandomR ) where

import Control.Arrow ((>>>))
import Control.Moffy (React, Request(..), await, adjust)
import Data.Type.Set (numbered, pattern Nil, Singleton, (:-))
import Data.OneOrMore (Selectable(..))
import System.Random (Random, StdGen, random, randomR)

---------------------------------------------------------------------------

-- * STORE RANDOM GEN
-- * LOAD RANDOM GEN
-- * RANDOM EV AND GET RANDOM

---------------------------------------------------------------------------
-- STORE RANDOM GEN
---------------------------------------------------------------------------

newtype StoreRandomGen = StoreRandomGenReq StdGen deriving Show
numbered [t| StoreRandomGen |]
instance Selectable StoreRandomGen where l `select` _r = l
instance Request StoreRandomGen where
	data Occurred StoreRandomGen = OccStoreRandomGen

storeRandomGen :: StdGen -> React s (Singleton StoreRandomGen) ()
storeRandomGen g = await (StoreRandomGenReq g) \OccStoreRandomGen -> ()

---------------------------------------------------------------------------
-- LOAD RANDOM GEN
---------------------------------------------------------------------------

data LoadRandomGen = LoadRandomGenReq deriving (Show, Eq, Ord)
numbered [t| LoadRandomGen |]
instance Request LoadRandomGen where
	data Occurred LoadRandomGen = OccLoadRandomGen StdGen

loadRandomGen :: React s (Singleton LoadRandomGen) StdGen
loadRandomGen = await LoadRandomGenReq \(OccLoadRandomGen g) -> g

---------------------------------------------------------------------------
-- RANDOM EV AND GET RANDOM
---------------------------------------------------------------------------

type RandomEv = StoreRandomGen :- LoadRandomGen :- 'Nil

getRandom :: Random a => React s RandomEv a
getRandom = modifyRandomGen random

getRandomR :: Random a => (a, a) -> React s RandomEv a
getRandomR = modifyRandomGen . randomR

modifyRandomGen :: (StdGen -> (a, StdGen)) -> React s RandomEv a
modifyRandomGen f = adjust loadRandomGen
	>>= (f >>> \(r, g) -> r <$ adjust (storeRandomGen g))