{-# LANGUAGE CPP #-}
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}
module Haxl.Core.Parallel
(
biselect
, pAnd
, pOr
, unsafeChooseFirst
) where
import Haxl.Core.Monad hiding (catch, throw)
import Haxl.Core.Exception
import Control.Exception (throw)
infixr 5 `pAnd`
infixr 4 `pOr`
biselect :: GenHaxl u w (Either a b)
-> GenHaxl u w (Either a c)
-> GenHaxl u w (Either a (b,c))
biselect haxla haxlb = biselect_opt id id Left Right haxla haxlb
{-# INLINE biselect_opt #-}
biselect_opt :: (l -> Either a b)
-> (r -> Either a c)
-> (a -> t)
-> ((b,c) -> t)
-> GenHaxl u w l
-> GenHaxl u w r
-> GenHaxl u w t
biselect_opt discrimA discrimB left right haxla haxlb =
let go (GenHaxl haxla) (GenHaxl haxlb) = GenHaxl $ \env@Env{..} -> do
ra <- haxla env
case ra of
Done ea ->
case discrimA ea of
Left a -> return (Done (left a))
Right b -> do
rb <- haxlb env
case rb of
Done eb ->
case discrimB eb of
Left a -> return (Done (left a))
Right c -> return (Done (right (b,c)))
Throw e -> return (Throw e)
Blocked ib haxlb' ->
return (Blocked ib
(haxlb' :>>= \b' -> go_right b b'))
Throw e -> return (Throw e)
Blocked ia haxla' -> do
rb <- haxlb env
case rb of
Done eb ->
case discrimB eb of
Left a -> return (Done (left a))
Right c ->
return (Blocked ia
(haxla' :>>= \a' -> go_left a' c))
Throw e -> return (Throw e)
Blocked ib haxlb' -> do
i <- newIVar
addJob env (return ()) i ia
addJob env (return ()) i ib
return (Blocked i (Cont (go (toHaxl haxla') (toHaxl haxlb'))))
go_right b eb =
case discrimB eb of
Left a -> return (left a)
Right c -> return (right (b,c))
go_left ea c =
case discrimA ea of
Left a -> return (left a)
Right b -> return (right (b,c))
in go haxla haxlb
pOr :: GenHaxl u w Bool -> GenHaxl u w Bool -> GenHaxl u w Bool
pOr x y = biselect_opt discrim discrim left right x y
where
discrim True = Left ()
discrim False = Right ()
left _ = True
right _ = False
pAnd :: GenHaxl u w Bool -> GenHaxl u w Bool -> GenHaxl u w Bool
pAnd x y = biselect_opt discrim discrim left right x y
where
discrim False = Left ()
discrim True = Right ()
left _ = False
right _ = True
unsafeChooseFirst
:: GenHaxl u w a
-> GenHaxl u w b
-> GenHaxl u w (Either a b)
unsafeChooseFirst x y = biselect_opt discrimx discrimy id right x y
where
discrimx :: a -> Either (Either a b) ()
discrimx a = Left (Left a)
discrimy :: b -> Either (Either a b) ()
discrimy b = Left (Right b)
right _ = throw $ CriticalError
"unsafeChooseFirst: We should never have a 'Right ()'"