bluefin 0.0.4.2 → 0.0.4.3
raw patch · 4 files changed
+85/−31 lines, 4 filesdep ~bluefin-internalPVP ok
version bump matches the API change (PVP)
Dependency ranges changed: bluefin-internal
API changes (from Hackage documentation)
Files
- CHANGELOG.md +4/−0
- bluefin.cabal +2/−2
- src/Bluefin.hs +73/−26
- src/Bluefin/Coroutine.hs +6/−3
CHANGELOG.md view
@@ -1,3 +1,7 @@+## 0.0.4.3++Improve documentation+ ## 0.0.4.2 * Depend on `bluefin-internal >= 0.0.4.2` so that Hackage will show
bluefin.cabal view
@@ -1,6 +1,6 @@ cabal-version: 3.0 name: bluefin-version: 0.0.4.2+version: 0.0.4.3 license: MIT license-file: LICENSE author: Tom Ellis@@ -34,6 +34,6 @@ Bluefin.Stream, Bluefin.Writer, build-depends:- bluefin-internal >= 0.0.4 && < 0.1+ bluefin-internal >= 0.0.4.2 && < 0.1 hs-source-dirs: src default-language: Haskell2010
src/Bluefin.hs view
@@ -2,14 +2,16 @@ ( -- * In brief -- | Bluefin is an effect system which allows you to freely mix a- -- variety of effects, accessed though value-level handles,- -- including+ -- variety of effects, including -- -- * "Bluefin.EarlyReturn", for early return -- * "Bluefin.Exception", for exceptions -- * "Bluefin.IO", for I/O -- * "Bluefin.State", for mutable state -- * "Bluefin.Stream", for streams+ --+ -- Bluefin effects are accessed through explicitly though+ -- value-level handles. -- * Introduction @@ -51,12 +53,14 @@ -- | A benefit of value-level effect handles is that it's simple -- to have multiple effects of the same type in scope at the same- -- time. It's easy to disambiguate them because they are distinct- -- values! It is not simple with existing effect systems because- -- they require the disambiguation to occur at the type level.- -- Here is an example with two mutable @Int@ state effects in- -- scope.+ -- time. It is simple to disambiguate them, because they are+ -- distinct values! By contrast, existing effect systems require+ -- the disambiguation to occur at the type level, which imposes+ -- challenges. --+ -- Here is a Bluefin example with two mutable @Int@ state effects+ -- in scope.+ -- -- @ -- -- Compare two values and add 10 -- -- to the smaller@@ -85,6 +89,48 @@ -- (30, 13) -- @ + -- ** Exception handles++ -- | Bluefin exceptions are accessed through+ -- 'Bluefin.Exception.Exception' handles. An @Exception@ handle+ -- is introduced by a handler, such as 'Bluefin.Exception.try',+ -- and that handler is where the exception, if thrown, will be+ -- handled. This arrangement differs from normal Haskell+ -- exceptions in two ways. Firstly, every Bluefin exception will+ -- be handled – it is not possible to have an unhandled Bluefin+ -- exception. Secondly, a Bluefin exception can be handled in+ -- only one place – normal Haskell exceptions can be handled in a+ -- variety of places, and the closest handler of matching type on+ -- the stack will be the one that will be chosen upon+ -- 'Control.Exception.throw'.+ --+ -- @example3@ shows how to use Bluefin to calculate the sum of+ -- numbers from 1 to @n@, but stop if the sum becomes bigger than+ -- 20. The exception handle, @ex@, which has type @Exception+ -- String e@, cannot escape the scope of its handler, @try@. If+ -- thrown it will be handled at that @try@, and nowhere else.+ --+ -- @+ -- example3 :: Int -> Either String Int+ -- example3 n = 'Bluefin.Eff.runPureEff' $+ -- 'Bluefin.Exception.try' $ \\ex -> do+ -- 'Bluefin.State.evalState' 0 $ \\total -> do+ -- for_ [1..n] $ \\i -> do+ -- soFar <- 'Bluefin.State.get' total+ -- when (soFar > 20) $ do+ -- 'Bluefin.Exception.throw' ex ("Became too big: " ++ show soFar)+ -- 'Bluefin.State.put' total (soFar + i)+ --+ -- 'Bluefin.State.get' total+ -- @+ --+ -- @+ -- >>> example3 4+ -- Right 10+ -- >>> example3 10+ -- Left "Became too big: 21"+ -- @+ -- ** Effect scoping -- | Bluefin's use of the type system is very similar to@@ -103,11 +149,11 @@ -- @ -- -- Here @\<Handle\>@ could be, for example, @State Int@,- -- @Exception String@ or @IOE@. Consider the example below,- -- @incrementReadLine@, which reads integers from standard input- -- and accumulates them into a state. It returns when it reads- -- the input integer @0@ and it throws an exception if it- -- encounters an input line it cannot parse.+ -- @Exception String@ or @IOE@. Consider the function below,+ -- @incrementReadLine@. It reads integers from standard input,+ -- accumulates them into a state; it returns when it reads the+ -- input integer @0@ and it throws an exception if it encounters+ -- an input line it cannot parse. -- -- Firstly, let's look at the arguments, which are all handles to -- Bluefin effects. There is a state handle, an exception handle,@@ -170,9 +216,10 @@ -- -- This means that the effect @e@, corresponding to the handle -- @\<Handle\> e@, has been handled and removed from the set of- -- remaining effects, @es@. (The signatures for @runEff@ and- -- @runPureEff@ are slightly different because they remove all- -- effects.)+ -- remaining effects, @es@. (The signatures for+ -- 'Bluefin.Eff.runEff' and 'Bluefin.Eff.runPureEff' are slightly+ -- different because they remove @Eff@ itself.) Here, then, is+ -- how we can run @incrementReadLine@: -- -- @ -- runIncrementReadLine :: IO (Either String Int)@@ -213,11 +260,13 @@ -- in effectful they are represented only at the type level. -- effectful could be described as "a well-typed implementation of -- the @ReaderT@ @IO@ pattern", and Bluefin could be described as- -- a well-typed implementation of something even simpler: "the- -- functions-that-return-@IO@ pattern". The aim of the Bluefin- -- style of value-level effect tracking is to make it even easier- -- to mix effects, especially effects of the same type. Only time- -- will tell which approach is preferable in practice.+ -- a well-typed implementation of something even simpler: the+ -- [Handle+ -- pattern](https://jaspervdj.be/posts/2018-03-08-handle-pattern.html).+ -- The aim of the Bluefin style of value-level effect tracking is+ -- to make it even easier to mix effects, especially effects of+ -- the same type. Only time will tell which approach is preferable+ -- in practice. -- Haddock seems to have trouble with italic sections spanning -- lines :(@@ -226,9 +275,8 @@ -- /top of effectful?/" -- -- It would be great to share code between the two projects! But- -- there are two Bluefin features that I don't know to implement- -- in terms of effectful: "Bluefin.Coroutine"s and- -- "Bluefin.Compound" effects.+ -- I don't know to implement Bluefin's "Bluefin.Compound" effects+ -- in effectful. -- * Implementation @@ -236,9 +284,8 @@ -- t'Bluefin.Eff.Eff' is an opaque wrapper around 'IO', -- t'Bluefin.State.State' is an opaque wrapper around -- 'Data.IORef.IORef', and 'Bluefin.Exception.throw' throws an- -- actual @IO@ exception. t'Bluefin.Coroutine.Coroutine', which- -- doesn't exist in effectful, is implemented simply as a- -- function.+ -- actual @IO@ exception. t'Bluefin.Coroutine.Coroutine' is+ -- implemented simply as a function. -- -- @ -- newtype t'Bluefin.Eff.Eff' (es :: 'Bluefin.Eff.Effects') a = 'Bluefin.Internal.UnsafeMkEff' (IO a)
src/Bluefin/Coroutine.hs view
@@ -1,8 +1,11 @@ module Bluefin.Coroutine ( -- | @Coroutine@ allows to yield values and receive results back.- -- It is not documented yet. You might want to start with- -- "Bluefin.Stream", which is the most common way to use- -- coroutines.+ -- [Wikipedia+ -- suggests](https://en.wikipedia.org/wiki/Coroutine#Definition_and_types)+ -- that Bluefin's coroutines are "second-class stackful+ -- coroutines". This module is not documented yet. You might+ -- want to start with "Bluefin.Stream", which is the most common+ -- way to use coroutines. -- * Handle Coroutine,