@@ -183,6 +183,9 @@ module Streamly.Internal.Data.Unfold
183183 , mapM
184184 , mapMWithInput
185185
186+ -- ** Either Wrapped Input
187+ , either
188+
186189 -- ** Filtering
187190 , takeWhileM
188191 , takeWhile
@@ -254,7 +257,7 @@ import Streamly.Internal.Data.SVar
254257import Streamly.Internal.Data.Unfold.Type
255258import Prelude
256259 hiding (map, mapM, takeWhile, take, filter, const, zipWith
257− , drop, dropWhile)
260+ , drop, dropWhile, either)
258261
259262-- $setup
260263-- >>> import qualified Streamly.Data.Fold as Fold
@@ -424,6 +427,36 @@ mapMWithInput f (Unfold ustep uinject) = Unfold step inject
424427 Skip s -> return $ Skip (inp, s)
425428 Stop -> return Stop
426429
430+
431+-------------------------------------------------------------------------------
432+-- Either
433+-------------------------------------------------------------------------------
434+
435+-- | Make an unfold operate on values wrapped in an @Either a a@ type. 'Right
436+-- a' translates to 'Right b' and 'Left a' translates to 'Left b'.
437+--
438+-- /Internal/
439+{-# INLINE_NORMAL either #-}
440+either :: Monad m => Unfold m a b -> Unfold m (Either a a) (Either b b)
441+either (Unfold step1 inject1) = Unfold step inject
442+
443+ where
444+
445+ inject (Left a) = do
446+ r <- inject1 a
447+ return (r, Left)
448+ inject (Right a) = do
449+ r <- inject1 a
450+ return (r, Right)
451+
452+ {-# INLINE_LATE step #-}
453+ step (st, f) = do
454+ r <- step1 st
455+ return $ case r of
456+ Yield x s -> Yield (f x) (s, f)
457+ Skip s -> Skip (s, f)
458+ Stop -> Stop
459+
427460-------------------------------------------------------------------------------
428461-- Convert streams into unfolds
429462-------------------------------------------------------------------------------