From 9771ed933898dbaec13edac0091b1562ddd28bdc Mon Sep 17 00:00:00 2001 From: Tom Ellis Date: Sat, 10 Feb 2024 12:04:53 +0000 Subject: [PATCH] Fix tests and more examples --- README.md | 2 + bluefin-internal/src/Bluefin/Internal.hs | 54 ++++++++++++++++++++++++ bluefin-internal/test/Main.hs | 16 +++---- 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 08cb160..8dd9e5c 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,8 @@ * Benchmarks (against `effectful` particularly) +* Doctests + # Acknowledgements * Oleg Kiselyov for his work on effects and delimited continuations diff --git a/bluefin-internal/src/Bluefin/Internal.hs b/bluefin-internal/src/Bluefin/Internal.hs index b850aa3..ce203ea 100644 --- a/bluefin-internal/src/Bluefin/Internal.hs +++ b/bluefin-internal/src/Bluefin/Internal.hs @@ -232,6 +232,12 @@ examplePut = runEff $ runState 10 $ \st -> do put st 30 pure () +-- | +-- @ +-- >>> runEff $ runState 10 $ \\st -> do +-- modify st (* 2) +-- ((), 20) +-- @ modify :: (st :> effs) => State s st -> @@ -242,6 +248,10 @@ modify state f = do s <- get state put state (f s) +modifyExample :: ((), Int) +modifyExample = runEff $ runState 10 $ \st -> do + modify st (* 2) + -- This is roughly how effectful does it data MyException where MyException :: e -> Data.Unique.Unique -> MyException @@ -260,6 +270,13 @@ withScopedException_ f = do -- unsafeCoerce is very unpleasant if tag == fresh then Just (unsafeCoerce e) else Nothing +-- | +-- @ +-- >>> runEff $ runState 10 $ \\st -> do +-- n <- get st +-- pure (2 * n) +-- (20,10) +-- @ runState :: -- | Initial state s -> @@ -282,6 +299,14 @@ yieldCoroutine :: Eff effs b yieldCoroutine (Coroutine f) a = Eff (f a) +-- | +-- @ +-- >>> runEff $ yieldToList $ \\y -> do +-- yield y 1 +-- yield y 2 +-- yield y 100 +-- ([1,2,100], ()) +-- @ yield :: (e1 :> effs) => Stream a e1 -> @@ -290,6 +315,12 @@ yield :: Eff effs () yield = yieldCoroutine +yieldExample :: ([Int], ()) +yieldExample = runEff $ yieldToList $ \y -> do + yield y 1 + yield y 2 + yield y 100 + handleCoroutine :: (a -> Eff effs b) -> (z -> Eff effs r) -> @@ -306,6 +337,11 @@ forEach :: Eff effs r forEach f h = unsafeRemoveEff (f (Coroutine (unsafeUnEff . h))) +-- | +-- @ +-- >>> runEff $ yieldToList $ inFoldable [1, 2, 100] +-- ([1, 2, 100], ()) +-- @ inFoldable :: (Foldable t, e1 :> effs) => -- | Yield all these values from the stream @@ -314,8 +350,16 @@ inFoldable :: Eff effs () inFoldable t = for_ t . yield +inFoldableExample :: ([Int], ()) +inFoldableExample = runEff $ yieldToList $ inFoldable [1, 2, 100] + -- | Pair each element in the stream with an increasing index, -- starting from 0. +-- +-- @ +-- >>> runEff $ yieldToList $ enumerate (inFoldable [\"A\", \"B\", \"C\"]) +-- ([(0, \"A\"), (1, \"B\"), (2, \"C\")], ()) +-- @ enumerate :: (e2 :> effs) => -- | ͘ @@ -327,6 +371,9 @@ enumerate ss st = evalState 0 $ \i -> forEach (insertSecond . ss) $ \s -> do yield st (ii, s) put i (ii + 1) +enumerateExample :: ([(Int, String)], ()) +enumerateExample = runEff $ yieldToList $ enumerate (inFoldable ["A", "B", "C"]) + handleException' :: (e -> r) -> (forall ex. Exception e ex -> Eff (ex :& effs) r) -> @@ -353,6 +400,13 @@ earlyReturn :: Eff effs a earlyReturn = throw +-- | +-- @ +-- >>> runEff $ evalState 10 $ \\st -> do +-- n <- get st +-- pure (2 * n) +-- 20 +-- @ evalState :: -- | Initial state s -> diff --git a/bluefin-internal/test/Main.hs b/bluefin-internal/test/Main.hs index c0bf12a..7903de8 100644 --- a/bluefin-internal/test/Main.hs +++ b/bluefin-internal/test/Main.hs @@ -16,12 +16,12 @@ main = do assert "index 2" ([0, 1, 2, 3] !? 4 == Nothing) assert "Exception 1" - ( runEff (handleException (eitherEff (Left True))) + ( runEff (try (eitherEff (Left True))) == (Left True :: Either Bool ()) ) assert "Exception 2" - ( runEff (handleException (eitherEff (Right True))) + ( runEff (try (eitherEff (Right True))) == (Right True :: Either () Bool) ) assert @@ -44,13 +44,13 @@ runTests f y = do evalState True $ \passedAllSoFar -> do forEach f $ \(name, passedThisOne) -> do unless passedThisOne $ - write passedAllSoFar False + put passedAllSoFar False let mark = if passedThisOne then "✓" else "✗" yield y (mark ++ " " ++ name) - read passedAllSoFar + get passedAllSoFar allTrue :: (forall e1 effs. Stream (String, Bool) e1 -> Eff (e1 :& effs) ()) -> @@ -68,9 +68,9 @@ xs !? i = runEff $ withEarlyReturn $ \ret -> do evalState 0 $ \s -> do for_ xs $ \a -> do - i' <- read s + i' <- get s when (i == i') (earlyReturn ret (Just a)) - write s (i' + 1) + put s (i' + 1) earlyReturn ret Nothing oddsUntilFirstGreaterThan5 :: [Int] @@ -94,9 +94,9 @@ eitherEff eith ex = case eith of stateEff :: (e1 :> effs) => (s -> (a, s)) -> State s e1 -> Eff effs a stateEff f st = do - s <- read st + s <- get st let (a, s') = f s - write st s' + put st s' pure a listEff :: (e1 :> effs) => ([a], r) -> Stream a e1 -> Eff effs r