-----------------------------------------------------------------------------
-- |
-- Module      :  Control.Monad.Trans.Cont.Speculation
-- Copyright   :  (C) 2011 Edward Kmett, Jake McArthur
-- License     :  BSD-style (see the file LICENSE)
--
-- Maintainer  :  Edward Kmett <ekmett@gmail.com>
-- Stability   :  provisional
-- Portability :  portable
--
-- Versions of the combinators from the 'speculation' package
-- with the signature rearranged to enable them to be used
-- directly as actions in the 'Cont' and 'ContT' monads.
----------------------------------------------------------------------------
module Control.Monad.Trans.Cont.Speculation where

import Control.Monad.Trans.Cont
import qualified Control.Concurrent.Speculation as Prim
import Control.Concurrent.STM

-- * Basic speculation

-- | When a is unevaluated, @'spec' g a@ evaluates the current continuation 
-- with @g@ while testing if @g@ '==' @a@, if they differ, it re-evalutes the
-- continuation with @a@. If @a@ was already evaluated, the continuation is
-- just directly applied to @a@ instead.
spec :: Eq a => a -> a -> ContT r m a
spec g a = ContT $ \k -> Prim.spec g k a 

-- | As per 'spec', without the check for whether or not the second argument
-- is already evaluated.
spec' :: Eq a => a -> a -> ContT r m a
spec' g a = ContT $ \k -> Prim.spec' g k a

-- | @spec@ with a user supplied comparison function
specBy :: (a -> a -> Bool) -> a -> a -> ContT r m a
specBy f g a = ContT $ \k -> Prim.specBy f g k a

-- | @spec'@ with a user supplied comparison function
specBy' :: (a -> a -> Bool) -> a -> a -> ContT r m a
specBy' f g a = ContT $ \k -> Prim.specBy' f g k a

-- | @spec'@ with a user supplied comparison function
specOn :: Eq c => (a -> c) -> a -> a -> ContT r m a
specOn f g a = ContT $ \k -> Prim.specOn f g k a

-- | @spec'@ with a user supplied comparison function
specOn' :: Eq c => (a -> c) -> a -> a -> ContT r m a
specOn' f g a = ContT $ \k -> Prim.specOn' f g k a

-- * STM-based speculation

specSTM :: Eq a => STM a -> a -> ContT r STM a
specSTM g a = ContT $ \k -> Prim.specSTM g k a 

specSTM' :: Eq a => STM a -> a -> ContT r STM a
specSTM' g a = ContT $ \k -> Prim.specSTM' g k a 

specOnSTM :: Eq c => (a -> STM c) -> STM a -> a -> ContT r STM a
specOnSTM f g a = ContT $ \k -> Prim.specOnSTM f g k a 

specOnSTM' :: Eq c => (a -> STM c) -> STM a -> a -> ContT r STM a
specOnSTM' f g a = ContT $ \k -> Prim.specOnSTM' f g k a 

specBySTM :: (a -> a -> STM Bool) -> STM a -> a -> ContT r STM a
specBySTM f g a = ContT $ \k -> Prim.specBySTM f g k a 

specBySTM' :: (a -> a -> STM Bool) -> STM a -> a -> ContT r STM a
specBySTM' f g a = ContT $ \k -> Prim.specBySTM' f g k a