bluefin 0.2.3.0 → 0.2.4.0
raw patch · 4 files changed
+102/−3 lines, 4 filesdep ~bluefin-internalPVP ok
version bump matches the API change (PVP)
Dependency ranges changed: bluefin-internal
API changes (from Hackage documentation)
+ Bluefin.CloneableHandle: MkGenericCloneableHandle :: h e -> GenericCloneableHandle (h :: k -> Type) (e :: k)
+ Bluefin.CloneableHandle: class Handle h => CloneableHandle (h :: Effects -> Type)
+ Bluefin.CloneableHandle: class Handle h => GCloneableHandle (h :: Effects -> Type)
+ Bluefin.CloneableHandle: class Generic1 (f :: k -> Type)
+ Bluefin.CloneableHandle: newtype GenericCloneableHandle (h :: k -> Type) (e :: k)
+ Bluefin.CloneableHandle: withEffToIOCloneHandle :: forall (e1 :: Effects) (es :: Effects) h a. (e1 :> es, CloneableHandle h) => IOE e1 -> h es -> ((forall r. () => (forall (e :: Effects). () => IOE e -> h e -> Eff e r) -> IO r) -> IO a) -> Eff es a
+ Bluefin.IO: withEffToIOCloneHandle :: forall (e1 :: Effects) (es :: Effects) h a. (e1 :> es, CloneableHandle h) => IOE e1 -> h es -> ((forall r. () => (forall (e :: Effects). () => IOE e -> h e -> Eff e r) -> IO r) -> IO a) -> Eff es a
Files
- CHANGELOG.md +5/−1
- bluefin.cabal +3/−2
- src/Bluefin/CloneableHandle.hs +92/−0
- src/Bluefin/IO.hs +2/−0
CHANGELOG.md view
@@ -1,4 +1,8 @@-# 0.2.1.0+# 0.2.4.0++* Add `Bluefin.CloneHandle` and `Bluefin.IO.withEffToIOCloneHandle`++# 0.2.3.0 * Add `Bluefin.DslBuilder`
bluefin.cabal view
@@ -1,6 +1,6 @@ cabal-version: 3.0 name: bluefin-version: 0.2.3.0+version: 0.2.4.0 license: MIT license-file: LICENSE author: Tom Ellis@@ -24,6 +24,7 @@ Bluefin.Compound, Bluefin.Consume, Bluefin.Coroutine,+ Bluefin.CloneableHandle, Bluefin.DslBuilder, Bluefin.EarlyReturn, Bluefin.Eff,@@ -40,6 +41,6 @@ Bluefin.System.IO, Bluefin.Writer, build-depends:- bluefin-internal >= 0.3.1.0 && < 0.4+ bluefin-internal >= 0.3.2.0 && < 0.4 hs-source-dirs: src default-language: Haskell2010
+ src/Bluefin/CloneableHandle.hs view
@@ -0,0 +1,92 @@+-- | @Bluefin.CloneableHandle@ defines the 'CloneableHandle' class,+-- whose purpose is to support 'withEffToIOCloneHandle'.++module Bluefin.CloneableHandle+ ( -- | 'withEffToIOCloneHandle' is an @IO@ unlifting function that+ -- clones its handle each time it runs @Eff@ in @IO@. This is+ -- convenient when the unlifting function is being used to fork+ -- threads, since Bluefin state is not threadsafe. Be careful+ -- when you use it, because it can be used to throw away the+ -- effect tag on a Bluefin @Eff@ action due to this part of+ -- its type (here throwing away @e@):+ --+ -- @+ -- (forall e. IOE e -> h e -> Eff e r) -> IO r+ -- @+ --+ -- It is only safely used when you do not allow any effects to+ -- escape their scope, so we suggest that you use it sparingly to+ -- define reusable combinators which themselves are safe. For+ -- example, here is how you could write an equivalent of @async@'s+ -- @race@ primitive:+ --+ -- @+ -- bluefinRace ::+ -- ('CloneableHandle' h, e1 :> es) =>+ -- t'Bluefin.IO.IOE' e1 ->+ -- h es ->+ -- (forall e. IOE e -> h e -> t'Bluefin.Eff.Eff' e r) ->+ -- (forall e. IOE e -> h e -> Eff e r) ->+ -- Eff es r+ -- bluefinRace io h m1 m2 = withEffToIOCloneHandle io h $ \\runInIO -> do+ -- either id id+ -- \<$\> Control.Concurrent.Async.race+ -- (runInIO $ \\io' h' -> m1 io' h')+ -- (runInIO $ \\io' h' -> m2 io' h')+ -- @+ --+ -- Then you can safely use it to race Bluefin @Eff@ actions:+ --+ -- @+ -- example :: IO ()+ -- example = 'Bluefin.Eff.runEff_' $ \\io -> 'Bluefin.State.evalState' 0 $ \\st -> do+ -- r \<- 'Bluefin.Exception.try' $ \\ex -> do+ -- bluefinRace+ -- io+ -- (MkMyHandle ('Bluefin.Handle.mapHandle' ex) (mapHandle st))+ -- ( \\_ (MkMyHandle ex' st') -> do+ -- 'Bluefin.State.modify' st' (subtract 2000)+ -- 'Bluefin.Exception.throw' ex' "Aborting from branch 1"+ -- )+ -- ( \\_ (MkMyHandle _ st') -> do+ -- modify st' (+ 3000)+ -- pure (2 :: Int)+ -- )+ --+ -- s <- 'Bluefin.State.get' st+ -- 'Bluefin.IO.effIO' io (print r)+ -- effIO io (putStrLn ("State started at 0 and was cloned. Now: " <> show s))+ -- @+ --+ -- You can see from the output that the actions were raced as+ -- expected, and the @State@ was cloned so that changes to it in+ -- the branches of @race@ did not affect the original @State@.+ --+ -- @+ -- -- Run one time (the first thread was faster)+ -- ghci> example+ -- Right 2+ -- State started at 0 and was cloned. Now: 0+ -- -- Run another time (the second thread was faster)+ -- ghci> example+ -- Left "Aborting from branch 1"+ -- State started at 0 and was cloned. Now: 0+ -- @+ --+ -- Note that @withEffToIOCloneHandle@ only allows access to /one/+ -- external @Handle@ within it, so if you have several you'd like+ -- to use you'll have to define a new handle that bundles them+ -- together.+ withEffToIOCloneHandle,++ -- * @CloneableHandle@+ CloneableHandle,+ GenericCloneableHandle(MkGenericCloneableHandle),+ GCloneableHandle,++ -- * @GHC.Generics@ re-exports+ Generic1,+ )+where++import Bluefin.Internal.CloneableHandle
src/Bluefin/IO.hs view
@@ -12,6 +12,7 @@ -- * IO type classes withMonadIO, withEffToIO_,+ withEffToIOCloneHandle, -- ** @EffReader@ EffReader, effReader,@@ -22,3 +23,4 @@ where import Bluefin.Internal+import Bluefin.Internal.CloneableHandle