@@ -53,13 +53,18 @@ module Control.Lens.SemiIso (
54 associated,
54 associated,
59import Control.Lens.Internal.SemiIso
62import Control.Lens.Internal.SemiIso
60import Control.Lens.Iso
63import Control.Lens.Iso
61import Data.Functor.Identity
65import Data.Functor.Identity
62import Data.Traversable
66import Data.Traversable
64-- | A semi-isomorphism is a partial isomorphism with weakened laws.
69-- | A semi-isomorphism is a partial isomorphism with weakened laws.
@@ -134,3 +139,23 @@ exact x = semiIso f g
134 f _ = Right x
139 f _ = Right x
135 g y | x == y = Right ()
140 g y | x == y = Right ()
136 | otherwise = Left "exact: not equal"
141 | otherwise = Left "exact: not equal"
143+-- | Constructs a bidirectional fold.
145+-- \-> Right folds using the (->) part of the given semi-iso.
147+-- \<- Right unfolds using the (<-) part of the given semi-iso.
148+bifoldr :: ASemiIso (b, a) (Maybe (b, a)) a a -> SemiIso' (a, [b]) a
149+bifoldr ai = semiIso (f ai) (g ai)
151+ f = uncurry . foldrM . curry . apply
152+ g = unfoldrM . unapply
154+ unfoldrM :: Monad m => (a -> m (Maybe (b, a))) -> a -> m (a, [b])
158+ Just (b, new_a) -> do
159+ (final_a, bs) <- unfoldrM f new_a
160+ return (final_a, b : bs)
161+ Nothing -> return (a, [])