haxl-2.0.0.0: Haxl/Core/Parallel.hs
-- Copyright (c) 2014-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is distributed under the terms of a BSD license,
-- found in the LICENSE file.
{-# LANGUAGE CPP #-}
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE RecordWildCards #-}
-- | Psuedo-parallel operations. Most users should import "Haxl.Core"
-- instead.
--
module Haxl.Core.Parallel
( -- * Parallel operations
pAnd
, pOr
) where
import Haxl.Core.Monad
-- -----------------------------------------------------------------------------
-- Parallel operations
-- Bind more tightly than .&&, .||
infixr 5 `pAnd`
infixr 4 `pOr`
-- | Parallel version of '(.||)'. Both arguments are evaluated in
-- parallel, and if either returns 'True' then the other is
-- not evaluated any further.
--
-- WARNING: exceptions may be unpredictable when using 'pOr'. If one
-- argument returns 'True' before the other completes, then 'pOr'
-- returns 'True' immediately, ignoring a possible exception that
-- the other argument may have produced if it had been allowed to
-- complete.
pOr :: GenHaxl u Bool -> GenHaxl u Bool -> GenHaxl u Bool
GenHaxl a `pOr` GenHaxl b = GenHaxl $ \env@Env{..} -> do
let !senv = speculate env
ra <- a senv
case ra of
Done True -> return (Done True)
Done False -> b env -- not speculative
Throw _ -> return ra
Blocked ia a' -> do
rb <- b senv
case rb of
Done True -> return rb
Done False -> return ra
Throw _ -> return rb
Blocked _ b' -> return (Blocked ia (Cont (toHaxl a' `pOr` toHaxl b')))
-- Note [pOr Blocked/Blocked]
-- This will only wake up when ia is filled, which
-- is whatever the left side was waiting for. This is
-- suboptimal because the right side might wake up first,
-- but handling this non-determinism would involve a much
-- more complicated implementation here.
-- | Parallel version of '(.&&)'. Both arguments are evaluated in
-- parallel, and if either returns 'False' then the other is
-- not evaluated any further.
--
-- WARNING: exceptions may be unpredictable when using 'pAnd'. If one
-- argument returns 'False' before the other completes, then 'pAnd'
-- returns 'False' immediately, ignoring a possible exception that
-- the other argument may have produced if it had been allowed to
-- complete.
pAnd :: GenHaxl u Bool -> GenHaxl u Bool -> GenHaxl u Bool
GenHaxl a `pAnd` GenHaxl b = GenHaxl $ \env@Env{..} -> do
let !senv = speculate env
ra <- a senv
case ra of
Done False -> return (Done False)
Done True -> b env
Throw _ -> return ra
Blocked ia a' -> do
rb <- b senv
case rb of
Done False -> return rb
Done True -> return ra
Throw _ -> return rb
Blocked _ b' -> return (Blocked ia (Cont (toHaxl a' `pAnd` toHaxl b')))
-- See Note [pOr Blocked/Blocked]