-- |
-- Copyright  : (c) Ivan Perez and Manuel Baerenz, 2016
-- License    : BSD3
-- Maintainer : ivan.perez@keera.co.uk
--
-- Versions of arrow combinators that run things in parallel using 'par', if
-- possible.
module Data.MonadicStreamFunction.Parallel where

-- External imports
import Control.Arrow (arr, (>>>))
import GHC.Conc      (par, pseq)

-- Internal imports
import Data.MonadicStreamFunction              ()
import Data.MonadicStreamFunction.InternalCore (MSF (MSF, unMSF))

-- | Run two 'MSF's in parallel, taking advantage of parallelism if possible.
-- This is the parallel version of '***'.
(*|*) :: Monad m => MSF m a b -> MSF m c d -> MSF m (a, c) (b, d)
MSF m a b
msf1 *|* :: forall (m :: * -> *) a b c d.
Monad m =>
MSF m a b -> MSF m c d -> MSF m (a, c) (b, d)
*|* MSF m c d
msf2 = forall (m :: * -> *) a b. (a -> m (b, MSF m a b)) -> MSF m a b
MSF forall a b. (a -> b) -> a -> b
$ \(a
a, c
c) -> do
  (b
b, MSF m a b
msf1') <- forall (m :: * -> *) a b. MSF m a b -> a -> m (b, MSF m a b)
unMSF MSF m a b
msf1 a
a
  (d
d, MSF m c d
msf2') <- forall (m :: * -> *) a b. MSF m a b -> a -> m (b, MSF m a b)
unMSF MSF m c d
msf2 c
c
  b
b forall a b. a -> b -> b
`par` d
d forall a b. a -> b -> b
`pseq` forall (m :: * -> *) a. Monad m => a -> m a
return ((b
b, d
d), MSF m a b
msf1' forall (m :: * -> *) a b c d.
Monad m =>
MSF m a b -> MSF m c d -> MSF m (a, c) (b, d)
*|* MSF m c d
msf2')

-- | Parallel version of '&&&'.
(&|&) :: Monad m => MSF m a b -> MSF m a c -> MSF m a (b, c)
MSF m a b
msf1 &|& :: forall (m :: * -> *) a b c.
Monad m =>
MSF m a b -> MSF m a c -> MSF m a (b, c)
&|& MSF m a c
msf2 = forall (a :: * -> * -> *) b c. Arrow a => (b -> c) -> a b c
arr (\a
a -> (a
a, a
a)) forall {k} (cat :: k -> k -> *) (a :: k) (b :: k) (c :: k).
Category cat =>
cat a b -> cat b c -> cat a c
>>> (MSF m a b
msf1 forall (m :: * -> *) a b c d.
Monad m =>
MSF m a b -> MSF m c d -> MSF m (a, c) (b, d)
*|* MSF m a c
msf2)