-- |
-- Module:     Control.Wire.Classes
-- Copyright:  (c) 2011 Ertugrul Soeylemez
-- License:    BSD3
-- Maintainer: Ertugrul Soeylemez <es@ertes.de>
--
-- Type classes used in Netwire.

module Control.Wire.Classes
    ( -- * Various effects
      ArrowClock(..),
      ArrowIO(..),
      ArrowRandom(..)
    )
    where

import Control.Arrow
import Control.Monad.IO.Class
import Data.Time.Clock.POSIX
import System.Random


-- | Arrows with a clock.

class Arrow (>~) => ArrowClock (>~) where
    -- | Type for time values.
    type Time (>~)

    -- | Current time in some arrow-specific frame of reference.
    arrTime :: a >~ Time (>~)


-- | Instance for the system time.  Use this only for testing.  This is
-- intentionally specific to allow you to define better instances with
-- custom arrows.

instance ArrowClock (Kleisli IO) where
    type Time (Kleisli IO) = Double
    arrTime = Kleisli (const $ fmap realToFrac getPOSIXTime)


-- | Arrows which support running IO computations.

class Arrow (>~) => ArrowIO (>~) where
    -- | Run the input IO computation and output its result.
    arrIO :: IO b >~ b

instance MonadIO m => ArrowIO (Kleisli m) where
    arrIO = Kleisli liftIO


-- | Arrows with support for random number generation.

class Arrow (>~) => ArrowRandom (>~) where
    -- | Return a random number.
    arrRand :: Random b => a >~ b

    -- | Return a random number in the input range.
    arrRandR :: Random b => (b, b) >~ b

-- | Instance for the 'IO'-builtin 'StdGen'.

instance ArrowRandom (Kleisli IO) where
    arrRand  = Kleisli (const randomIO)
    arrRandR = Kleisli randomRIO