{-# LANGUAGE LambdaCase #-} {-# LANGUAGE RankNTypes #-} module Control.Lens.FileSystem.Internal.Combinators where import Control.Lens import Control.Lens.Action import Control.Lens.Action.Internal import Control.Applicative -- | If a given fold fails (e.g. with an exception), recover and simply return 0 elements -- rather than crashing. recovering :: (Monad m, Alternative m, Monoid r, Effective m r f) => Over' p f s a -> Over' p f s a recovering fld f s = effective (ineffective (fld f s) <|> pure mempty) -- | Try the given fold, if it throws an exception then return the input as the output instead tryOrContinue :: (Monad m, Alternative m) => Acting m r a a -> Acting m r a a tryOrContinue = flip tryCatch pure -- | Try the given fold, if it throws an exception then use the given handler to compute a -- replacement value and continue with that. tryCatch :: (Monad m, Alternative m) => Acting m r s b -> (s -> m b) -> Acting m r s b tryCatch fld handler f a = effective (ineffective (fld f a) <|> (handler a >>= ineffective . f)) -- | Filter a fold using a monadic action filteredM :: (Monad m, Monoid r) => (a -> m Bool) -> Acting m r a a filteredM predicate f a = effective go where go = do predicate a >>= \case True -> ineffective (f a) False -> pure mempty -- | Merge two folds merging :: (Applicative f, Contravariant f) => LensLike' f s a -> LensLike' f s a -> LensLike' f s a merging fold1 fold2 nextFold s = fold1 nextFold s *> fold2 nextFold s -- | Include the results of an additional fold alongside the original values including :: (Applicative f, Contravariant f) => LensLike' f a a -> LensLike' f a a including = merging id