bluefin-internal 0.0.1.0 → 0.0.2.0
raw patch · 3 files changed
+149/−4 lines, 3 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
+ Bluefin.Internal: StateSource :: StateSource (st :: Effects)
+ Bluefin.Internal: data StateSource (st :: Effects)
+ Bluefin.Internal: newState :: StateSource e -> s -> Eff es (State s e)
+ Bluefin.Internal: withStateSource :: (forall e. StateSource e -> Eff (e :& es) a) -> Eff es a
+ Bluefin.Internal.Examples: countExampleI :: IO ()
+ Bluefin.Internal.Examples: evalStateI :: s -> (forall st. (?st :: State s st) => Eff (st :& es) a) -> Eff es a
+ Bluefin.Internal.Examples: getI :: forall st s es. st :> es => (?st :: State s st) => Eff es s
+ Bluefin.Internal.Examples: modifyI :: forall st s es. st :> es => (?st :: State s st) => (s -> s) -> Eff es ()
+ Bluefin.Internal.Examples: stateSourceExample :: Int
+ Bluefin.Internal.Examples: throwI :: e1 :> es => (?ex :: Exception e e1) => e -> Eff es a
+ Bluefin.Internal.Examples: while :: Eff es Bool -> Eff es a -> Eff es ()
Files
- bluefin-internal.cabal +3/−1
- src/Bluefin/Internal.hs +49/−2
- src/Bluefin/Internal/Examples.hs +97/−1
bluefin-internal.cabal view
@@ -1,6 +1,6 @@ cabal-version: 3.0 name: bluefin-internal-version: 0.0.1.0+version: 0.0.2.0 license: MIT license-file: LICENSE author: Tom Ellis@@ -9,6 +9,8 @@ extra-doc-files: CHANGELOG.md description: The Bluefin effect system, internals synopsis: The Bluefin effect system, internals+homepage: https://github.com/tomjaguarpaw/bluefin+bug-reports: https://github.com/tomjaguarpaw/bluefin/issues common defaults ghc-options: -Wall
src/Bluefin/Internal.hs view
@@ -161,6 +161,9 @@ pushFirst :: Eff a r -> Eff (a :& b) r pushFirst = weakenEff (fstI (# #)) +-- | Handle to a capability to create strict mutable state handles+data StateSource (st :: Effects) = StateSource+ -- | Handle to an exception of type @e@ newtype Exception e (ex :: Effects) = Exception (forall a. e -> IO a) @@ -372,6 +375,50 @@ -- | -- @+-- runPureEff $ withStateSource $ \\source -> do+-- n <- newState source 5+-- total <- newState source 0+--+-- 'Bluefin.Jump.withJump' $ \\done -> forever $ do+-- n' <- 'Bluefin.State.get' n+-- 'Bluefin.State.modify' total (+ n')+-- when (n' == 0) $ 'Bluefin.Jump.jumpTo' done+-- modify n (subtract 1)+--+-- get total+-- 15+-- @+withStateSource ::+ (forall e. StateSource e -> Eff (e :& es) a) ->+ -- | ͘+ Eff es a+withStateSource f = unsafeRemoveEff (f StateSource)++-- |+-- @+-- runPureEff $ withStateSource $ \\source -> do+-- n <- newState source 5+-- total <- newState source 0+--+-- 'Bluefin.Jump.withJump' $ \\done -> forever $ do+-- n' <- 'Bluefin.State.get' n+-- 'Bluefin.State.modify' total (+ n')+-- when (n' == 0) $ 'Bluefin.Jump.jumpTo' done+-- modify n (subtract 1)+--+-- get total+-- 15+-- @+newState ::+ StateSource e ->+ -- | The initial value for the state handle+ s ->+ -- | A new state handle+ Eff es (State s e)+newState StateSource s = UnsafeMkEff (fmap UnsafeMkState (newIORef s))++-- |+-- @ -- >>> runPureEff $ runState 10 $ \\st -> do -- n <- get st -- pure (2 * n)@@ -385,8 +432,8 @@ -- | Result and final state Eff es (a, s) runState s f = do- state <- UnsafeMkEff (fmap UnsafeMkState (newIORef s))- unsafeRemoveEff $ do+ withStateSource $ \source -> do+ state <- newState source s a <- f state s' <- get state pure (a, s')
src/Bluefin/Internal/Examples.hs view
@@ -1,10 +1,11 @@ {-# LANGUAGE NoMonoLocalBinds #-} {-# LANGUAGE NoMonomorphismRestriction #-}+{-# LANGUAGE ImplicitParams #-} module Bluefin.Internal.Examples where import Bluefin.Internal hiding (w)-import Control.Monad (forever, when)+import Control.Monad (forever, unless, when) import Control.Monad.IO.Class (liftIO) import Data.Foldable (for_) import Data.Monoid (Any (Any, getAny))@@ -187,6 +188,32 @@ myInc h myBail h +throwI ::+ (e1 :> es) =>+ (?ex :: Exception e e1) =>+ -- | Value to throw+ e ->+ Eff es a+throwI = throw ?ex++modifyI ::+ forall st s es.+ (st :> es) =>+ (?st :: State s st) =>+ -- | Apply this function to the state. The new value of the state+ -- is forced before writing it to the state.+ (s -> s) ->+ Eff es ()+modifyI = modify ?st++getI ::+ forall st s es.+ (st :> es) =>+ (?st :: State s st) =>+ -- | The current value of the state+ Eff es s+getI = get ?st+ countExample :: IO () countExample = runEff $ \io -> do evalState @Int 0 $ \sn -> do@@ -203,3 +230,72 @@ writerExample2 :: Bool writerExample2 = getAny $ runPureEff $ execWriter $ \w -> do for_ [1 .. 10] $ \_ -> tell w (Any True)++while :: Eff es Bool -> Eff es a -> Eff es ()+while condM body =+ withJump $ \break_ -> do+ forever $ do+ cond <- insertFirst condM+ unless cond (jumpTo break_)+ insertFirst body++stateSourceExample :: Int+stateSourceExample = runPureEff $ withStateSource $ \source -> do+ n <- newState source 5+ total <- newState source 0++ withJump $ \done -> forever $ do+ n' <- get n+ modify total (+ n')+ when (n' == 0) $ jumpTo done+ modify n (subtract 1)++ get total++-- welltypedwitch raised the intriguing possibility of using+-- ImplicitParams to avoid having to pass effect handles explicitly.+-- Unfortunately I've been snagged on two issues:+--+-- 1. It doesn't seem possible to bind an implicit parameter in a+-- lambda. (See+-- https://discourse.haskell.org/t/why-cant-an-implicitparam-be-bound-by-a-lambda/8936/2)+--+-- 2. Type inference gets stuck. I don't understand why.+countExampleI :: IO ()+countExampleI = runEff $ ((\io -> do+ evalState @Int 0 $ ((\st -> do+ let ?st = st+ withJump $ \break -> forever $ do+ n <- getI @st+ when (n >= 10) (jumpTo break)+ effIO io (print n)+ modifyI @st (+ 1))+ :: forall st. State Int st -> Eff (st :& e :& es) ()))+ :: forall e es. IOE e -> Eff (e :& es) ())++-- We might want to resolve 1 by putting the ImplicitParam as an+-- argument to the handler, but I can't work out how to get that to+-- type check at all+evalStateI ::+ -- | Initial state+ s ->+ -- | Stateful computation+ (forall st. (?st :: State s st) => Eff (st :& es) a) ->+ -- | Result+ Eff es a+evalStateI s f = evalState s (\x -> let ?st = x in f)++-- This just doesn't work. Have a made a silly mistake?++{-+countExampleI2 :: IO ()+countExampleI2 = runEff $ ((\io -> do+ evalStateI @Int 0 $ (do+ withJump $ \break -> forever $ do+ n <- getI @st+ when (n >= 10) (jumpTo break)+ effIO io (print n)+ modifyI @st (+ 1))+ :: forall st. (?st :: State Int st) => Eff (st :& e :& effes) ())+ :: forall e effes. IOE e -> Eff (e :& effes) ())+-}