packages feed

reactive-thread-0.3.1.0: Reactive/Thread/Internal/Thread.hs

{-# LANGUAGE GADTs #-}

module Reactive.Thread.Internal.Thread
  ( Thread
  , fork
  , yield
  , runThread
  ) where

import Control.Monad
import Control.Monad.IO.Class
import Control.Monad.Parallel
import Control.Monad.Trans.Class

import Reactive.Thread.Internal.VarSource

-- | A thread of execution.
data Thread v o m a where
  Pure :: a -> Thread v o m a
  Lift :: m (Thread v o m a) -> Thread v o m a
  Yield :: o -> Thread v o m a -> Thread v o m a

  Fork
    :: Thread v b m ()  -- ^ Thread computation.
    -> v b              -- ^ Output variable.
    -> Thread v o m a   -- ^ Rest.
    -> Thread v o m a

instance (Monad m) => Monad (Thread v o m) where
  return = Pure

  Pure x >>= f = f x
  Lift m >>= f = Lift (m >>= \ t -> return (t >>= f))
  Yield x m >>= f = Yield x (m >>= f)
  Fork thread var m >>= f = Fork thread var (m >>= f)

instance (Functor m) => Functor (Thread v o m) where
  fmap f (Pure x) = Pure $ f x
  fmap f (Lift m) = Lift $ fmap (fmap f) m
  fmap f (Yield x m) = Yield x $ fmap f m
  fmap f (Fork thread var m) = Fork thread var $ fmap f m

instance MonadTrans (Thread v o) where
  lift m = Lift (liftM Pure m)

instance (MonadIO m) => MonadIO (Thread v o m) where
  liftIO = lift . liftIO

-- | Creates a new thread which executes in parallel,
-- returning the forked thread's output variable.
fork
  :: (Functor m, Monad m, NewVar v m)
  => b                   -- ^ Initial value.
  -> Thread v b m a      -- ^ Computation to fork.
  -> Thread v o m (v b)  -- ^ Var.
fork z m = do
  var <- lift $ newVar z
  Fork (void m) var (Pure var)

-- | Yields a value to this thread's output variable.
yield :: (Monad m) => o -> Thread v o m ()
yield x = Yield x (return ())

-- | Executes a thread in the parent monad.
runThread
  :: ( MonadFork m
     , WriteVar v m
     )
  => v o             -- ^ Output variable.
  -> Thread v o m a
  -> m a
runThread output = go
  where
    go (Pure x) = return x
    go (Lift m) = m >>= go
    go (Yield x m) = writeVar output x >> go m
    go (Fork thread var m)
      = forkExec (runThread var thread) >> go m