bluefin-internal 0.0.6.0 → 0.0.6.1
raw patch · 4 files changed
+95/−36 lines, 4 filesPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
API changes (from Hackage documentation)
+ Bluefin.Internal.Examples: polymorphicBracket :: st :> es => State (Integer, Bool) st -> Eff es () -> Eff es ()
+ Bluefin.Internal.Examples: polymorphicBracketExample1 :: (Integer, Bool)
+ Bluefin.Internal.Examples: polymorphicBracketExample2 :: (Integer, Bool)
- Bluefin.Internal: MkCoroutine :: (a -> Eff s b) -> Coroutine a b (s :: Effects)
+ Bluefin.Internal: MkCoroutine :: (a -> Eff e b) -> Coroutine a b (e :: Effects)
- Bluefin.Internal: StateSource :: StateSource (st :: Effects)
+ Bluefin.Internal: StateSource :: StateSource (e :: Effects)
- Bluefin.Internal: UnsafeMkException :: (forall a. e -> IO a) -> Exception e (ex :: Effects)
+ Bluefin.Internal: UnsafeMkException :: (forall a. exn -> IO a) -> Exception exn (e :: Effects)
- Bluefin.Internal: UnsafeMkState :: IORef s -> State s (st :: Effects)
+ Bluefin.Internal: UnsafeMkState :: IORef s -> State s (e :: Effects)
- Bluefin.Internal: catch :: forall e (es :: Effects) a. (forall ex. Exception e ex -> Eff (ex :& es) a) -> (e -> Eff es a) -> Eff es a
+ Bluefin.Internal: catch :: forall exn (es :: Effects) a. (forall e. Exception exn e -> Eff (e :& es) a) -> (exn -> Eff es a) -> Eff es a
- Bluefin.Internal: data StateSource (st :: Effects)
+ Bluefin.Internal: data StateSource (e :: Effects)
- Bluefin.Internal: evalState :: s -> (forall st. State s st -> Eff (st :& es) a) -> Eff es a
+ Bluefin.Internal: evalState :: s -> (forall e. State s e -> Eff (e :& es) a) -> Eff es a
- Bluefin.Internal: get :: st :> es => State s st -> Eff es s
+ Bluefin.Internal: get :: e :> es => State s e -> Eff es s
- Bluefin.Internal: handle :: forall e (es :: Effects) a. (e -> Eff es a) -> (forall ex. Exception e ex -> Eff (ex :& es) a) -> Eff es a
+ Bluefin.Internal: handle :: forall exn (es :: Effects) a. (exn -> Eff es a) -> (forall e. Exception exn e -> Eff (e :& es) a) -> Eff es a
- Bluefin.Internal: jumpTo :: j :> es => Jump j -> Eff es a
+ Bluefin.Internal: jumpTo :: e :> es => Jump e -> Eff es a
- Bluefin.Internal: modify :: st :> es => State s st -> (s -> s) -> Eff es ()
+ Bluefin.Internal: modify :: e :> es => State s e -> (s -> s) -> Eff es ()
- Bluefin.Internal: newtype Coroutine a b (s :: Effects)
+ Bluefin.Internal: newtype Coroutine a b (e :: Effects)
- Bluefin.Internal: newtype Exception e (ex :: Effects)
+ Bluefin.Internal: newtype Exception exn (e :: Effects)
- Bluefin.Internal: newtype State s (st :: Effects)
+ Bluefin.Internal: newtype State s (e :: Effects)
- Bluefin.Internal: put :: st :> es => State s st -> s -> Eff es ()
+ Bluefin.Internal: put :: e :> es => State s e -> s -> Eff es ()
- Bluefin.Internal: returnEarly :: er :> es => EarlyReturn r er -> r -> Eff es a
+ Bluefin.Internal: returnEarly :: e :> es => EarlyReturn r e -> r -> Eff es a
- Bluefin.Internal: runState :: s -> (forall st. State s st -> Eff (st :& es) a) -> Eff es (a, s)
+ Bluefin.Internal: runState :: s -> (forall e. State s e -> Eff (e :& es) a) -> Eff es (a, s)
- Bluefin.Internal: try :: forall e (es :: Effects) a. (forall ex. Exception e ex -> Eff (ex :& es) a) -> Eff es (Either e a)
+ Bluefin.Internal: try :: forall exn (es :: Effects) a. (forall e. Exception exn e -> Eff (e :& es) a) -> Eff es (Either exn a)
- Bluefin.Internal: unwrap :: j :> es => Jump j -> Maybe a -> Eff es a
+ Bluefin.Internal: unwrap :: e :> es => Jump e -> Maybe a -> Eff es a
- Bluefin.Internal: withEarlyReturn :: (forall er. EarlyReturn r er -> Eff (er :& es) r) -> Eff es r
+ Bluefin.Internal: withEarlyReturn :: (forall e. EarlyReturn r e -> Eff (e :& es) r) -> Eff es r
- Bluefin.Internal: withJump :: (forall j. Jump j -> Eff (j :& es) ()) -> Eff es ()
+ Bluefin.Internal: withJump :: (forall e. Jump e -> Eff (e :& es) ()) -> Eff es ()
Files
- CHANGELOG.md +4/−0
- bluefin-internal.cabal +2/−2
- src/Bluefin/Internal.hs +59/−34
- src/Bluefin/Internal/Examples.hs +30/−0
CHANGELOG.md view
@@ -1,3 +1,7 @@+## 0.0.6.1++* Documentation improvements+ ## 0.0.6.0 * Add `withYieldToList`
bluefin-internal.cabal view
@@ -1,6 +1,6 @@ cabal-version: 3.0 name: bluefin-internal-version: 0.0.6.0+version: 0.0.6.1 license: MIT license-file: LICENSE author: Tom Ellis@@ -77,7 +77,7 @@ default-language: Haskell2010 hs-source-dirs: src build-depends:- base >= 4.12 && < 4.20,+ base >= 4.12 && < 4.21, unliftio-core < 0.3, transformers < 0.7, transformers-base < 0.5,
src/Bluefin/Internal.hs view
@@ -35,6 +35,7 @@ type (:&) = Union type role Eff nominal representational+ newtype Eff (es :: Effects) a = UnsafeMkEff {unsafeUnEff :: IO a} deriving stock (Functor) deriving newtype (Applicative, Monad)@@ -184,17 +185,17 @@ useImplIn f h = inContext (f h) -- | Handle to a capability to create strict mutable state handles-data StateSource (st :: Effects) = StateSource+data StateSource (e :: Effects) = StateSource --- | Handle to an exception of type @e@-newtype Exception e (ex :: Effects) = UnsafeMkException (forall a. e -> IO a)+-- | Handle to an exception of type @exn@+newtype Exception exn (e :: Effects) = UnsafeMkException (forall a. exn -> IO a) --- | A handle to a strict mutable state of type @a@-newtype State s (st :: Effects) = UnsafeMkState (IORef s)+-- | A handle to a strict mutable state of type @s@+newtype State s (e :: Effects) = UnsafeMkState (IORef s) -- | A handle to a coroutine that expects values of type @a@ and then -- yields values of type @b@.-newtype Coroutine a b (s :: Effects) = MkCoroutine (a -> Eff s b)+newtype Coroutine a b (e :: Effects) = MkCoroutine (a -> Eff e b) -- | A handle to a stream that yields values of type @a@. It is -- implemented as a handle to a coroutine that expects values of type@@ -237,7 +238,6 @@ -- fmap per @->@ that appears in type of the dynamic effect. That is, -- @queryDatabase@ has type @String -> Int -> Eff e [String]@, which -- has two @->@, so there are two @fmap@s before @useImpl@.- class Handle (h :: Effects -> Type) where -- | Used to create compound effects, i.e. handles that contain -- other handles.@@ -356,10 +356,10 @@ -- Left 42 -- @ try ::- forall e (es :: Effects) a.- (forall ex. Exception e ex -> Eff (ex :& es) a) ->+ forall exn (es :: Effects) a.+ (forall e. Exception exn e -> Eff (e :& es) a) -> -- | @Left@ if the exception was thrown, @Right@ otherwise- Eff es (Either e a)+ Eff es (Either exn a) try f = UnsafeMkEff $ withScopedException_ (\throw_ -> unsafeUnEff (f (UnsafeMkException throw_))) @@ -372,10 +372,10 @@ -- "42" -- @ handle ::- forall e (es :: Effects) a.+ forall exn (es :: Effects) a. -- | If the exception is thrown, apply this handler- (e -> Eff es a) ->- (forall ex. Exception e ex -> Eff (ex :& es) a) ->+ (exn -> Eff es a) ->+ (forall e. Exception exn e -> Eff (e :& es) a) -> Eff es a handle h f = try f >>= \case@@ -383,10 +383,10 @@ Right a -> pure a catch ::- forall e (es :: Effects) a.- (forall ex. Exception e ex -> Eff (ex :& es) a) ->+ forall exn (es :: Effects) a.+ (forall e. Exception exn e -> Eff (e :& es) a) -> -- | If the exception is thrown, apply this handler- (e -> Eff es a) ->+ (exn -> Eff es a) -> Eff es a catch f h = handle h f @@ -395,13 +395,38 @@ -- exception. This is essentially the same as -- @Control.Exception.'Control.Exception.bracket'@, whose -- documentation you can inspect for further details.+--+-- @bracket@ has a very general type that does not require @es@ to+-- contain an exception or IO effect. The reason that this is safe is:+--+-- * While @bracket@ does catch exceptions, this is unobservable,+-- since the exception is re-thrown; the cleanup action happens+-- unconditionally; and no part of it gets access to the thrown+-- exception.+--+-- * 'Eff' itself is able to guarantee that any exceptions thrown+-- in the body will be actually thrown before @bracket@+-- exits. This is inherited from the fact that @Eff@ is a wrapper+-- around 'IO'.+--+-- While it is usually the case that the cleanup action will in fact+-- want to use @IO@ effects, this is not universally true, see the+-- @polymorphicBracket@ example for an example. bracket ::+ -- | Acquire the resource Eff es a ->+ -- | Release the resource (a -> Eff es ()) ->+ -- | Run the body (a -> Eff es b) ->+ -- | Eff es b-bracket before after body = UnsafeMkEff $ Control.Exception.bracket- (unsafeUnEff before) (unsafeUnEff . after) (unsafeUnEff . body)+bracket before after body =+ UnsafeMkEff $+ Control.Exception.bracket+ (unsafeUnEff before)+ (unsafeUnEff . after)+ (unsafeUnEff . body) -- | -- @@@ -411,8 +436,8 @@ -- (20,10) -- @ get ::- (st :> es) =>- State s st ->+ (e :> es) =>+ State s e -> -- | The current value of the state Eff es s get (UnsafeMkState r) = UnsafeMkEff (readIORef r)@@ -425,8 +450,8 @@ -- ((), 30) -- @ put ::- (st :> es) =>- State s st ->+ (e :> es) =>+ State s e -> -- | The new value of the state. The new value is forced before -- writing it to the state. s ->@@ -440,8 +465,8 @@ -- ((), 20) -- @ modify ::- (st :> es) =>- State s st ->+ (e :> es) =>+ State s e -> -- | Apply this function to the state. The new value of the state -- is forced before writing it to the state. (s -> s) ->@@ -523,7 +548,7 @@ -- | Initial state s -> -- | Stateful computation- (forall st. State s st -> Eff (st :& es) a) ->+ (forall e. State s e -> Eff (e :& es) a) -> -- | Result and final state Eff es (a, s) runState s f = do@@ -644,7 +669,7 @@ -- "Returned early with 5" -- @ withEarlyReturn ::- (forall er. EarlyReturn r er -> Eff (er :& es) r) ->+ (forall e. EarlyReturn r e -> Eff (e :& es) r) -> -- | ͘ Eff es r withEarlyReturn = handle pure@@ -659,8 +684,8 @@ -- "Returned early with 5" -- @ returnEarly ::- (er :> es) =>- EarlyReturn r er ->+ (e :> es) =>+ EarlyReturn r e -> -- | Return early to the handler, with this value. r -> Eff es a@@ -677,7 +702,7 @@ -- | Initial state s -> -- | Stateful computation- (forall st. State s st -> Eff (st :& es) a) ->+ (forall e. State s e -> Eff (e :& es) a) -> -- | Result Eff es a evalState s f = fmap fst (runState s f)@@ -779,7 +804,7 @@ -- | -- @--- >>> runPureEff $ withYieldToList $ \y -> do+-- >>> runPureEff $ withYieldToList $ \\y -> do -- yield y 1 -- yield y 2 -- yield y 100@@ -868,7 +893,7 @@ -- 15 -- @ withJump ::- (forall j. Jump j -> Eff (j :& es) ()) ->+ (forall e. Jump e -> Eff (e :& es) ()) -> -- | ͘ Eff es () withJump = withEarlyReturn@@ -889,13 +914,13 @@ -- 15 -- @ jumpTo ::- (j :> es) =>- Jump j ->+ (e :> es) =>+ Jump e -> -- | ͘ Eff es a jumpTo tag = throw tag () -unwrap :: (j :> es) => Jump j -> Maybe a -> Eff es a+unwrap :: (e :> es) => Jump e -> Maybe a -> Eff es a unwrap j = \case Nothing -> jumpTo j Just a -> pure a
src/Bluefin/Internal/Examples.hs view
@@ -616,3 +616,33 @@ applicationState = mapHandle a, logger = mapHandle l }++-- This example shows a case where we can use @bracket@ polymorphically+-- in order to perform correct cleanup if @es@ is instantiated to a+-- set of effects that includes exceptions.+polymorphicBracket ::+ (st :> es) =>+ State (Integer, Bool) st ->+ Eff es () ->+ Eff es ()+polymorphicBracket st act =+ bracket+ (pure ())+ -- Always set the boolean indicating that we have terminated+ (\_ -> modify st (\(c, b) -> (c, True)))+ -- Perform the given effectful action, then increment the counter+ (\_ -> do act; modify st (\(c, b) -> ((c + 1), b)))++-- Results in (1, True)+polymorphicBracketExample1 :: (Integer, Bool)+polymorphicBracketExample1 =+ runPureEff $ do+ (_res, st) <- runState (0, False) $ \st -> polymorphicBracket st (pure ())+ pure st++-- Results in (0, True)+polymorphicBracketExample2 :: (Integer, Bool)+polymorphicBracketExample2 =+ runPureEff $ do+ (_res, st) <- runState (0, False) $ \st -> try $ \e -> polymorphicBracket st (throw e 42)+ pure st