-- |
-- 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 *|* :: MSF m a b -> MSF m c d -> MSF m (a, c) (b, d)
*|* MSF m c d
msf2 = ((a, c) -> m ((b, d), MSF m (a, c) (b, d))) -> MSF m (a, c) (b, d)
forall (m :: * -> *) a b. (a -> m (b, MSF m a b)) -> MSF m a b
MSF (((a, c) -> m ((b, d), MSF m (a, c) (b, d)))
 -> MSF m (a, c) (b, d))
-> ((a, c) -> m ((b, d), MSF m (a, c) (b, d)))
-> MSF m (a, c) (b, d)
forall a b. (a -> b) -> a -> b
$ \(a
a, c
c) -> do
  (b
b, MSF m a b
msf1') <- MSF m a b -> a -> m (b, MSF m a b)
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') <- MSF m c d -> c -> m (d, MSF m c d)
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 b
-> m ((b, d), MSF m (a, c) (b, d))
-> m ((b, d), MSF m (a, c) (b, d))
forall a b. a -> b -> b
`par` d
d d
-> m ((b, d), MSF m (a, c) (b, d))
-> m ((b, d), MSF m (a, c) (b, d))
forall a b. a -> b -> b
`pseq` ((b, d), MSF m (a, c) (b, d)) -> m ((b, d), MSF m (a, c) (b, d))
forall (m :: * -> *) a. Monad m => a -> m a
return ((b
b, d
d), MSF m a b
msf1' MSF m a b -> MSF m c d -> MSF m (a, c) (b, d)
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 &|& :: MSF m a b -> MSF m a c -> MSF m a (b, c)
&|& MSF m a c
msf2 = (a -> (a, a)) -> MSF m a (a, a)
forall (a :: * -> * -> *) b c. Arrow a => (b -> c) -> a b c
arr (\a
a -> (a
a, a
a)) MSF m a (a, a) -> MSF m (a, a) (b, c) -> MSF m a (b, c)
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 MSF m a b -> MSF m a c -> MSF m (a, a) (b, c)
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)