unamb 0.1.2 → 0.1.3
raw patch · 3 files changed
+36/−61 lines, 3 filesPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
API changes (from Hackage documentation)
- Data.Unamb: bottom :: a
- Data.Unamb: hang :: a
Files
- src/Data/Unamb.hs +34/−59
- tests/Tests.hs +1/−1
- unamb.cabal +1/−1
src/Data/Unamb.hs view
@@ -16,11 +16,11 @@ -- '''lub''' package. ---------------------------------------------------------------------- -#include "Typeable.h"+-- #include "Typeable.h" module Data.Unamb (- bottom, unamb, assuming, asAgree, hang+ unamb, assuming, asAgree , amb, race -- * Some useful special applications of 'amb' , parCommute, por, pand@@ -28,34 +28,37 @@ import Prelude hiding (catch) import System.IO.Unsafe-+import Data.Function (on)+import Control.Monad.Instances () -- for function functor import Control.Concurrent import Control.Exception- (evaluate, BlockedOnDeadMVar(..), catch, throw)+ (evaluate, ErrorCall(..), BlockedOnDeadMVar(..), catch, throw) -- | Unambiguous choice operator. Equivalent to the ambiguous choice -- operator, but with arguments restricted to be equal where not bottom, -- so that the choice doesn't matter. See also 'amb'. unamb :: a -> a -> a-a `unamb` b = unsafePerformIO (a `amb` b)+unamb = (fmap.fmap) unsafePerformIO amb +-- a `unamb` b = unsafePerformIO (a `amb` b) + -- | Ambiguous choice operator. Yield either value. Evaluates in -- separate threads and picks whichever finishes first. See also -- 'unamb' and 'race'. amb :: a -> a -> IO a-a `amb` b = evaluate a `race` evaluate b+amb = race `on` evaluate +-- a `amb` b = evaluate a `race` evaluate b+ -- | Race two actions against each other in separate threads, and pick--- whichever finishes first. See also 'amb'. Thanks to Spencer Janssen--- for this simple version.+-- whichever finishes first. See also 'amb'. race :: IO a -> IO a -> IO a- a `race` b = do v <- newEmptyMVar- ta <- forkIO' (a >>= putMVar v)- tb <- forkIO' (b >>= putMVar v)- x <- takeMVar v+ ta <- forkPut a v+ tb <- forkPut b v+ x <- takeMVar v killThread ta killThread tb return x@@ -71,58 +74,26 @@ -- and easier debugging. --- Fork a thread to execute a given action. Silence any raised exceptions.-forkIO' :: IO () -> IO ThreadId-forkIO' act = forkIO (act `catch` handler)+-- Fork a thread to execute a given action and store the result in an+-- MVar. Catch 'undefined', bypassing the MVar write. Two racing two+-- aborted threads in this way can result in 'BlockedOnDeadMVar', so catch+-- that exception also.+forkPut :: IO a -> MVar a -> IO ThreadId+forkPut act v = forkIO ((act >>= putMVar v) `catch` uhandler `catch` bhandler) where- handler :: BlockedOnDeadMVar -> IO ()- handler = const (return ())---- I'd like @hang `unamb` hang@ to quickly terminate, throwing an--- exception. I'm surprised that it doesn't lead to 'BlockedOnDeadMVar'.--- Why doesn't it?? Oh -- maybe it does, when compiled.----- | A 'bottom' value, allowing no information out. A left- and right---- identity for 'unamb'. At the top level, evaluating 'bottom' results in--- the message "Exception: thread blocked indefinitely".-bottom :: a-bottom = throw BlockedOnDeadMVar---- {-# DEPRECATED hang "use bottom instead" #-}---- | Never yield an answer. Like 'undefined' or 'error "whatever"', but--- don't raise an error, and don't consume computational resources.-hang :: a-hang = bottom+ uhandler (ErrorCall "Prelude.undefined") = return ()+ uhandler err = throw err+ bhandler BlockedOnDeadMVar = return () -- | Yield a value if a condition is true. Otherwise wait forever. assuming :: Bool -> a -> a-assuming c a = if c then a else hang+assuming c a = if c then a else undefined -- | The value of agreeing values (or hang) asAgree :: Eq a => a -> a -> a a `asAgree` b = assuming (a == b) a ----- -{---import Data.Dynamic -- move up--data WaitForever = WaitForever--INSTANCE_TYPEABLE0(WaitForever,waitForeverTc,"WaitForever")--instance Show WaitForever where- showsPrec _ WaitForever = showString "waiting for, like, evar"-instance Exception WaitForever---}-------- {-------------------------------------------------------------------- Some useful special applications of 'unamb' --------------------------------------------------------------------}@@ -136,8 +107,12 @@ -- | Parallel or por :: Bool -> Bool -> Bool-por = parCommute (||) +a `por` b = (a || b) `unamb` (b || a)+++-- por = parCommute (||)+ -- | Parallel and pand :: Bool -> Bool -> Bool pand = parCommute (&&)@@ -146,11 +121,11 @@ -- Examples: -bottom `por` True-True `por` bottom+undefined `por` True+True `por` undefined -bottom `pand` False-False `pand` bottom+undefined `pand` False+False `pand` undefined -}
tests/Tests.hs view
@@ -24,7 +24,7 @@ batch :: TestBatch batch = ( "FRP.Reactive.Unamb"- , [ ("both identity", bothId unambt hang)+ , [ ("both identity", bothId unambt undefined) , ("idempotence" , idempotent2 unambt) , ("commutative" , isCommutTimes 0.00001 unambt) , ("associative" , isAssocTimes 0.00001 unambt)
unamb.cabal view
@@ -1,5 +1,5 @@ Name: unamb-Version: 0.1.2+Version: 0.1.3 Cabal-Version: >= 1.2 Synopsis: Unambiguous choice Category: Concurrency, Data, Other