Skip to content

Commit

Permalink
Example of dynamic effect with handle as argument
Browse files Browse the repository at this point in the history
Should resolve #17
  • Loading branch information
tomjaguarpaw committed Nov 15, 2024
1 parent 9f791d7 commit c67b2a5
Show file tree
Hide file tree
Showing 2 changed files with 164 additions and 0 deletions.
75 changes: 75 additions & 0 deletions bluefin-internal/src/Bluefin/Internal/Examples.hs
Original file line number Diff line number Diff line change
Expand Up @@ -734,6 +734,81 @@ exampleCounter6 = runPureEff $ yieldToList $ \y -> do
-- > 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
Expand Down
89 changes: 89 additions & 0 deletions bluefin/src/Bluefin/Compound.hs
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,95 @@ module Bluefin.Compound
-- (["Count was even","I'm getting the counter","n was 2, as expected"],2)
-- @

-- ** Dynamic effects with handles as arguments

-- | We can implement dynamic effects that themselves take handles
-- as arguments, by giving all the handle arguments the effect tag
-- @e'@.
--
-- @
-- 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
-- @
--
-- The result is the same as before ...
--
-- @
-- 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)
-- @
--
-- ... unless we run @incCounter@ too many times, in which case it
-- throws can exception.
--
-- @
-- 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)
-- @

-- ** A dynamic file system effect

-- | The @effectful@ library has [an example of a dynamic effect
Expand Down

0 comments on commit c67b2a5

Please sign in to comment.