From 2947532cf200e77f3d3db9ba4805ec73e14a1e00 Mon Sep 17 00:00:00 2001 From: Giulio Foresto Date: Mon, 20 Sep 2021 23:00:38 +0200 Subject: [PATCH] feat(SourceT): add fromConsumableActionStep that creates a StepT from an action that consumes some data --- .../generalize-fromActionStep-to-consumable | 22 ++++++++++++++++++ servant/src/Servant/Types/SourceT.hs | 23 +++++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 changelog.d/generalize-fromActionStep-to-consumable diff --git a/changelog.d/generalize-fromActionStep-to-consumable b/changelog.d/generalize-fromActionStep-to-consumable new file mode 100644 index 00000000..6218a0d3 --- /dev/null +++ b/changelog.d/generalize-fromActionStep-to-consumable @@ -0,0 +1,22 @@ +synopsis: Add a `StepT` constructor method that consumes a resource +prs: #1533 +issues: #1448 + +description: { + +`fromActionStep` always runs the same action, which makes it impossible with such monadic actions to +"consume" a resource (that is to say to pass the modified resource to the following action), or +"unfold" an input structure. + +`unfoldStep` gives this possibility. + +This allows for example to build a `StepT m` directly from a `Streaming.Prelude.Stream`, by passing +`unfoldStep` the following argument: + +```haskell +import Streaming.Prelude as S + +action :: Stream (Of a) m r -> m (Maybe ( a, Stream (Of a) m r )) +action = S.uncons +``` +} \ No newline at end of file diff --git a/servant/src/Servant/Types/SourceT.hs b/servant/src/Servant/Types/SourceT.hs index 84cb4b6a..324e46fc 100644 --- a/servant/src/Servant/Types/SourceT.hs +++ b/servant/src/Servant/Types/SourceT.hs @@ -2,6 +2,7 @@ {-# LANGUAGE GADTs #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE TupleSections #-} module Servant.Types.SourceT where import Control.Monad.Except @@ -312,6 +313,28 @@ fromActionStep stop action = loop where | otherwise = Yield x loop {-# INLINE fromActionStep #-} +-- | Create a `StepT' from a consumable @c@, that is to say from an input and an action that returns +-- and is called again on an updated version of that input. +-- +-- >>> import qualified Streaming.Prelude as S +-- >>> foreachStep mempty print (unfoldStep S.uncons $ S.each [1..3] :: StepT IO Int) +-- 1 +-- 2 +-- 3 +-- +unfoldStep :: Functor m + => (c -> m (Maybe (a,c))) + -- ^ Action. Return @Nothing@ to stop or @Just (a,c)@ where @a@ is the + -- output element of the action and @c@ the updated input + -> c + -- ^ Input + -> StepT m a +unfoldStep action = loop where + loop c = Effect $ step <$> action c + step Nothing = Stop + step (Just (x,t)) = Yield x $ loop t +{-# INLINE unfoldStep #-} + ------------------------------------------------------------------------------- -- File -------------------------------------------------------------------------------