bluefin-internal 0.0.10.0 → 0.0.11.0
raw patch · 4 files changed
+148/−21 lines, 4 filesPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
API changes (from Hackage documentation)
+ Bluefin.Internal: makeOp :: Eff (e :& e) r -> Eff e r
+ Bluefin.Internal: subsume2 :: (e1 `In` e2) -> (e1 :& e2) `In` e2
+ Bluefin.Internal: useImplUnder :: e :> es => Eff (e1 :& e) r -> Eff (e1 :& es) r
+ Bluefin.Internal: withEffToIO_ :: e :> es => IOE e -> ((forall r. Eff es r -> IO r) -> IO a) -> Eff es a
+ Bluefin.Internal: withEffToIO_' :: e2 :> es => IOE e2 -> ((forall r. (forall e1. IOE e1 -> Eff (e1 :& es) r) -> IO r) -> IO a) -> Eff es a
+ Bluefin.Internal.Examples: MkCounter7 :: (forall e'. Exception () e' -> Eff (e' :& e) ()) -> State Int e -> Stream String e -> Counter7 e
+ Bluefin.Internal.Examples: [counter7State] :: Counter7 e -> State Int e
+ Bluefin.Internal.Examples: [counter7Stream] :: Counter7 e -> Stream String e
+ Bluefin.Internal.Examples: [incCounter7Impl] :: Counter7 e -> forall e'. Exception () e' -> Eff (e' :& e) ()
+ Bluefin.Internal.Examples: data Counter7 e
+ Bluefin.Internal.Examples: exampleCounter7A :: ([String], Int)
+ Bluefin.Internal.Examples: exampleCounter7B :: ([String], Int)
+ Bluefin.Internal.Examples: getCounter7 :: e :> es => Counter7 e -> String -> Eff es Int
+ Bluefin.Internal.Examples: incCounter7 :: (e :> es, e1 :> es) => Counter7 e -> Exception () e1 -> Eff es ()
+ Bluefin.Internal.Examples: instance Bluefin.Internal.Handle Bluefin.Internal.Examples.Counter5
+ Bluefin.Internal.Examples: instance Bluefin.Internal.Handle Bluefin.Internal.Examples.Counter6
+ Bluefin.Internal.Examples: instance Bluefin.Internal.Handle Bluefin.Internal.Examples.Counter7
+ Bluefin.Internal.Examples: runCounter7 :: e1 :> es => Stream String e1 -> (forall e. Counter7 e -> Eff (e :& es) r) -> Eff es Int
- Bluefin.Internal.Examples: MkApplication :: (String -> Int -> Eff e [String]) -> State (Int, Bool) e -> Stream String e -> Application e
+ Bluefin.Internal.Examples: MkApplication :: (forall e'. String -> Int -> Eff (e' :& e) [String]) -> State (Int, Bool) e -> Stream String e -> Application e
- Bluefin.Internal.Examples: MkCounter5 :: Eff e () -> (String -> Eff e Int) -> Counter5 e
+ Bluefin.Internal.Examples: MkCounter5 :: (forall e'. Eff (e' :& e) ()) -> (forall e'. String -> Eff (e' :& e) Int) -> Counter5 e
- Bluefin.Internal.Examples: MkCounter6 :: Eff e () -> State Int e -> Stream String e -> Counter6 e
+ Bluefin.Internal.Examples: MkCounter6 :: (forall e'. Eff (e' :& e) ()) -> State Int e -> Stream String e -> Counter6 e
- Bluefin.Internal.Examples: [getCounter5Impl] :: Counter5 e -> String -> Eff e Int
+ Bluefin.Internal.Examples: [getCounter5Impl] :: Counter5 e -> forall e'. String -> Eff (e' :& e) Int
- Bluefin.Internal.Examples: [incCounter5Impl] :: Counter5 e -> Eff e ()
+ Bluefin.Internal.Examples: [incCounter5Impl] :: Counter5 e -> forall e'. Eff (e' :& e) ()
- Bluefin.Internal.Examples: [incCounter6Impl] :: Counter6 e -> Eff e ()
+ Bluefin.Internal.Examples: [incCounter6Impl] :: Counter6 e -> forall e'. Eff (e' :& e) ()
- Bluefin.Internal.Examples: [queryDatabase] :: Application e -> String -> Int -> Eff e [String]
+ Bluefin.Internal.Examples: [queryDatabase] :: Application e -> forall e'. String -> Int -> Eff (e' :& e) [String]
Files
- CHANGELOG.md +6/−0
- bluefin-internal.cabal +1/−1
- src/Bluefin/Internal.hs +43/−12
- src/Bluefin/Internal/Examples.hs +98/−8
CHANGELOG.md view
@@ -1,3 +1,9 @@+## 0.0.11.0++* Add `withEffToIO_`, `useImplUnder`, `makeOp`++* Soft deprecate `withEffToIO`, `useImplWithin`+ ## 0.0.10.0 * Add `Bluefin.Internal.System.IO`
bluefin-internal.cabal view
@@ -1,6 +1,6 @@ cabal-version: 3.0 name: bluefin-internal-version: 0.0.10.0+version: 0.0.11.0 license: MIT license-file: LICENSE author: Tom Ellis
src/Bluefin/Internal.hs view
@@ -58,7 +58,7 @@ runEffReader :: r -> EffReader r es a -> Eff es a runEffReader r (MkEffReader m) = m r --- This is possibly what @withRunInIO@ should morally be.+-- | Deprecated. Use @withEffToIO_@ instead. withEffToIO :: (e2 :> es) => -- | Continuation with the unlifting function in scope.@@ -75,8 +75,29 @@ Eff es a withEffToIO' io k = withEffToIO k io +withEffToIO_ ::+ (e :> es) =>+ IOE e ->+ -- | Continuation with the unlifting function in scope.+ ((forall r. Eff es r -> IO r) -> IO a) ->+ Eff es a+withEffToIO_ io k =+ withEffToIO (\effToIO -> k (\eff -> effToIO (\_ -> useImpl eff))) io++-- We can do the old API in terms of withEffToIO_+withEffToIO_' ::+ (e2 :> es) =>+ IOE e2 ->+ -- | Continuation with the unlifting function in scope.+ ((forall r. (forall e1. IOE e1 -> Eff (e1 :& es) r) -> IO r) -> IO a) ->+ Eff es a+withEffToIO_' io k =+ withEffToIO_ io (\effToIO -> k (\eff -> effToIO (weakenEff (subsume2 has) (eff io))))+ -- We don't try to do anything sophisticated here. I haven't thought -- through all the consequences.++-- | You probably want to use 'withEffToIO_' instead. instance (e :> es) => MonadUnliftIO (EffReader (IOE e) es) where withRunInIO :: ((forall a. EffReader (IOE e) es a -> IO a) -> IO b) ->@@ -261,9 +282,21 @@ inContext = weakenEff (subsume1 has) -- | Used to define dynamic effects.+makeOp :: Eff (e :& e) r -> Eff e r+makeOp = inContext++-- | Used to define dynamic effects. useImpl :: (e :> es) => Eff e r -> Eff es r useImpl = weakenEff has +-- | Like 'useImpl'+useImplUnder ::+ (e :> es) =>+ Eff (e1 :& e) r ->+ -- | ͘+ Eff (e1 :& es) r+useImplUnder = insertManySecond+ -- | Used to define handlers of compound effects. useImplIn :: (e :> es) =>@@ -273,7 +306,7 @@ Eff es r useImplIn f h = inContext (f h) --- | Like 'useImplIn'+-- | Deprecated. Use 'useImplUnder' instead. useImplWithin :: (e :> es) => (t -> Eff (e1 :& e) r) ->@@ -309,15 +342,15 @@ -- -- @ -- data Application e = MkApplication--- { queryDatabase :: String -> Int -> Eff e [String],+-- { queryDatabase :: forall e'. String -> Int -> Eff (e' :& e) [String], -- applicationState :: State (Int, Bool) e, -- logger :: Stream String e -- } -- @ -- -- To define @mapHandle@ for @Application@ you should apply--- @mapHandle@ to all the fields that are themeselevs handles and--- apply @useImpl@ to all the fields that are dynamic effects:+-- @mapHandle@ to all the fields that are themeselves handles and+-- apply @useImplUnder@ to all the fields that are dynamic effects: -- -- @ -- instance Handle Application where@@ -328,16 +361,11 @@ -- logger = l -- } = -- MkApplication--- { queryDatabase = (fmap . fmap) useImpl q,+-- { queryDatabase = \s i -> useImplUnder (q s i), -- applicationState = mapHandle a, -- logger = mapHandle l -- } -- @------ Note that preceding @useImpl@ on the dynamic effect there is one--- 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.@@ -402,6 +430,9 @@ subsume1 :: (e2 `In` e1) -> (e1 :& e2) `In` e1 subsume1 i = cmp (bimap (eq (# #)) i) (merge (# #)) +subsume2 :: (e1 `In` e2) -> (e1 :& e2) `In` e2+subsume2 i = cmp (bimap i (eq (# #))) (merge (# #))+ -- | Effect subset constraint class (es1 :: Effects) :> (es2 :: Effects) @@ -520,7 +551,7 @@ -- @ -- -- @--- Caught ErrorCall:+-- Caught IOException: -- \/tmp\/doesnt-exist: openFile: does not exist (No such file or directory) -- @ rethrowIO ::
src/Bluefin/Internal/Examples.hs view
@@ -614,15 +614,22 @@ -- Counter 5 data Counter5 e = MkCounter5- { incCounter5Impl :: Eff e (),- getCounter5Impl :: String -> Eff e Int+ { incCounter5Impl :: forall e'. Eff (e' :& e) (),+ getCounter5Impl :: forall e'. String -> Eff (e' :& e) Int } +instance Handle Counter5 where+ mapHandle c =+ MkCounter5+ { incCounter5Impl = useImplUnder (incCounter5Impl c),+ getCounter5Impl = \msg -> useImplUnder (getCounter5Impl c msg)+ }+ incCounter5 :: (e :> es) => Counter5 e -> Eff es ()-incCounter5 e = useImpl (incCounter5Impl e)+incCounter5 e = makeOp (incCounter5Impl (mapHandle e)) getCounter5 :: (e :> es) => Counter5 e -> String -> Eff es Int-getCounter5 e msg = useImpl (getCounter5Impl e msg)+getCounter5 e msg = makeOp (getCounter5Impl (mapHandle e) msg) runCounter5 :: (e1 :> es) =>@@ -667,13 +674,21 @@ -- Counter 6 data Counter6 e = MkCounter6- { incCounter6Impl :: Eff e (),+ { incCounter6Impl :: forall e'. Eff (e' :& e) (), counter6State :: State Int e, counter6Stream :: Stream String e } +instance Handle Counter6 where+ mapHandle c =+ MkCounter6+ { incCounter6Impl = useImplUnder (incCounter6Impl c),+ counter6State = mapHandle (counter6State c),+ counter6Stream = mapHandle (counter6Stream c)+ }+ incCounter6 :: (e :> es) => Counter6 e -> Eff es ()-incCounter6 e = useImpl (incCounter6Impl e)+incCounter6 e = makeOp (incCounter6Impl (mapHandle e)) getCounter6 :: (e :> es) => Counter6 e -> String -> Eff es Int getCounter6 (MkCounter6 _ st y) msg = do@@ -719,6 +734,81 @@ -- > exampleCounter6 -- (["Count was even","I'm getting the counter","n was 2, as expected"],2) +-- Counter 7++data Counter7 e = MkCounter7+ { incCounter7Impl :: forall e'. Exception () e' -> Eff (e' :& e) (),+ counter7State :: State Int e,+ counter7Stream :: Stream String e+ }++instance Handle Counter7 where+ mapHandle c =+ MkCounter7+ { incCounter7Impl = \ex -> useImplUnder (incCounter7Impl c ex),+ counter7State = mapHandle (counter7State c),+ counter7Stream = mapHandle (counter7Stream c)+ }++incCounter7 ::+ (e :> es, e1 :> es) => Counter7 e -> Exception () e1 -> Eff es ()+incCounter7 e ex = makeOp (incCounter7Impl (mapHandle e) (mapHandle ex))++getCounter7 :: (e :> es) => Counter7 e -> String -> Eff es Int+getCounter7 (MkCounter7 _ st y) msg = do+ yield y msg+ get st++runCounter7 ::+ (e1 :> es) =>+ Stream String e1 ->+ (forall e. Counter7 e -> Eff (e :& es) r) ->+ Eff es Int+runCounter7 y k =+ evalState 0 $ \st -> do+ _ <-+ useImplIn+ k+ ( MkCounter7+ { incCounter7Impl = \ex -> do+ count <- get st++ when (even count) $+ yield y "Count was even"++ when (count >= 10) $+ throw ex ()++ put st (count + 1),+ counter7State = mapHandle st,+ counter7Stream = mapHandle y+ }+ )+ get st++exampleCounter7A :: ([String], Int)+exampleCounter7A = runPureEff $ yieldToList $ \y -> do+ handle (\() -> pure (-42)) $ \ex ->+ runCounter7 y $ \c -> do+ incCounter7 c ex+ incCounter7 c ex+ n <- getCounter7 c "I'm getting the counter"+ when (n == 2) $+ yield y "n was 2, as expected"++-- > exampleCounter7A+-- (["Count was even","I'm getting the counter","n was 2, as expected"],2)++exampleCounter7B :: ([String], Int)+exampleCounter7B = runPureEff $ yieldToList $ \y -> do+ handle (\() -> pure (-42)) $ \ex ->+ runCounter7 y $ \c -> do+ forever (incCounter7 c ex)++-- > exampleCounter7B+-- (["Count was even","Count was even","Count was even","Count was even","Count was even","Count was even"],-42)++ -- FileSystem data FileSystem es = MkFileSystem@@ -802,7 +892,7 @@ -- instance Handle example data Application e = MkApplication- { queryDatabase :: String -> Int -> Eff e [String],+ { queryDatabase :: forall e'. String -> Int -> Eff (e' :& e) [String], applicationState :: State (Int, Bool) e, logger :: Stream String e }@@ -815,7 +905,7 @@ logger = l } = MkApplication- { queryDatabase = (fmap . fmap) useImpl q,+ { queryDatabase = \s i -> useImplUnder (q s i), applicationState = mapHandle a, logger = mapHandle l }