oath 0.0 → 0.1.1
raw patch · 4 files changed
+24/−10 lines, 4 filesdep ~basePVP ok
version bump matches the API change (PVP)
Dependency ranges changed: base
API changes (from Hackage documentation)
+ Oath: tryOath :: Exception e => Oath a -> Oath (Either e a)
- Oath: hoistOath :: (forall x. STM x -> STM x) -> Oath a -> Oath a
+ Oath: hoistOath :: (STM a -> STM b) -> Oath a -> Oath b
Files
- CHANGELOG.md +6/−1
- README.md +4/−4
- oath.cabal +3/−3
- src/Oath.hs +11/−2
CHANGELOG.md view
@@ -1,5 +1,10 @@ # Revision history for oath -## 0.1.0.0 -- YYYY-mm-dd+## 0.1++* Generalised the type of `hoistOath`+* Added `tryOath`++## 0.0 -- YYYY-mm-dd * First version. Released on an unsuspecting world.
README.md view
@@ -9,7 +9,7 @@ `Oath` is a continuation-passing IO action which takes a transaction to obtain the final result (`STM a`). The continuation-passing style makes it easier to release resources in time.-The easiest way to construct `Oath` is `oath`. It run the supplied action in a separate thread as long as the continuation is running.+The easiest way to construct `Oath` is `oath`. It runs the supplied IO action in a separate thread as long as the continuation is running. ```haskell oath :: IO a -> Oath a@@ -23,7 +23,7 @@ evalOath m = runOath m atomically ``` -`Oath` is an `Applicative`, so you can combine multiple `Oath`s. It starts computations without waiting for the results. Run `evalOath` to get the final result. The following code run concurrently `foo :: IO a` and `bar :: IO b`, then applies `f` to these results.+`Oath` is an `Applicative`, so you can combine multiple `Oath`s using `<*>`. `Oath` combined this way kicks off computations without waiting for the results. The following code runs `foo :: IO a` and `bar :: IO b` concurrently, then applies `f` to these results. ```haskell main = evalOath $ f <$> oath foo <*> oath bar@@ -40,7 +40,7 @@ Oath $ \cont -> bracket sendRequest cancelRequest (cont . waitForResponse) ``` -Timeout behaviour can be easily added using the `Alternative` instance and `delay :: Int -> Oath ()`. Or more in general, `<|>` runs both computations until one of them finishes.+Timeout behaviour can be easily added using the `Alternative` instance and `delay :: Int -> Oath ()`. `a <|> b` runs both computations until one of them returns a result, then cancels the other. ```haskell -- | An 'Oath' that finishes once the given number of microseconds elapses@@ -62,7 +62,7 @@ [futures](https://hackage.haskell.org/package/futures-0.1/docs/Futures.html) provides a wrapper of `forkIO`. There is no way to terminate an action and it does not propagate exceptions. -[promise](https://hackage.haskell.org/package/promise-0.1.0.0/docs/Control-Concurrent-Promise.html) has illegal Applicative and Monad instances; `(<*>)` is not associative and has a bind that's not consistent with `(<*>).`+[promise](https://hackage.haskell.org/package/promise-0.1.0.0/docs/Control-Concurrent-Promise.html) has illegal Applicative and Monad instances; `(<*>)` is not associative and its `ap` is not consistent with `(<*>)`. Performance ----
oath.cabal view
@@ -1,6 +1,6 @@ cabal-version: 2.4 name: oath-version: 0.0+version: 0.1.1 -- A short (one-line) description of the package. synopsis: Composable concurrent computation done right@@ -17,7 +17,7 @@ maintainer: fumiexcel@gmail.com -- A copyright notice.-copyright: Copyright (c) 2021 Fumiaki Kinoshita+copyright: Copyright (c) 2022 Fumiaki Kinoshita category: Concurrency extra-source-files: CHANGELOG.md, README.md @@ -32,7 +32,7 @@ -- LANGUAGE extensions used by modules in this package. -- other-extensions:- build-depends: base >=4.14.1.0 && <4.17, stm, stm-delay+ build-depends: base >=4.14.1.0 && <4.18, stm, stm-delay hs-source-dirs: src default-language: Haskell2010 ghc-options: -Wall -Wcompat
src/Oath.hs view
@@ -5,6 +5,7 @@ ( Oath(..) , hoistOath , evalOath+ , tryOath , oath , delay , timeout) where@@ -21,16 +22,24 @@ deriving Functor deriving (Semigroup, Monoid) via Ap Oath a -hoistOath :: (forall x. STM x -> STM x) -> Oath a -> Oath a+-- | Apply a function to the inner computation that waits for the result.+hoistOath :: (STM a -> STM b) -> Oath a -> Oath b hoistOath t (Oath m) = Oath $ \cont -> m $ cont . t +-- | Run an 'Oath' and wait for the result. evalOath :: Oath a -> IO a evalOath m = runOath m atomically +-- | Catch an exception thrown in the inner computation.+tryOath :: Exception e => Oath a -> Oath (Either e a)+tryOath = hoistOath $ \t -> fmap Right t `catchSTM` (pure . Left)++-- | ('<*>') initiates both computations, then combines the results once they are done instance Applicative Oath where pure a = Oath $ \cont -> cont (pure a) Oath m <*> Oath n = Oath $ \cont -> m $ \f -> n $ \x -> cont (f <*> x) +-- | ('<|>') waits for the first result, then cancel the loser instance Alternative Oath where empty = Oath $ \cont -> cont empty Oath m <|> Oath n = Oath $ \cont -> m $ \a -> n $ \b -> cont (a <|> b)@@ -49,6 +58,6 @@ delay :: Int -> Oath () delay dur = Oath $ \cont -> bracket (newDelay dur) cancelDelay (cont . waitDelay) --- | Wrap an 'Oath'+-- | Returns nothing if the 'Oath' does not finish within the given number of microseconds. timeout :: Int -> Oath a -> Oath (Maybe a) timeout dur m = Just <$> m <|> Nothing <$ delay dur