1

Is there a standard / optimized implementation of the following function that I'm writing (probably unnecessarily):

filterFirstM :: (Monad m, Foldable t) => (a -> Bool) -> t m a -> m a
filterFirstM predicate actions = foldlM fn Nothing actions
  where
    fn memo action = case memo of
      Just _ -> pure memo
      Nothing -> do
        x <- action
        pure $ if predicate x then (Just x) else Nothing

Sample usage:

filterFirstM (== 1) [pure 0 :: IO Int, pure 1, error "not evaluated"] == (pure 1)
Saurabh Nanda
  • 6,373
  • 5
  • 31
  • 60
  • 1
    Didn't you just ask that question? [Standard combinator to get first "non-empty" value from a set of monadic actions](https://stackoverflow.com/questions/59798367/standard-combinator-to-get-first-non-empty-value-from-a-set-of-monadic-actions) – Mark Seemann Jan 18 '20 at 12:54
  • Actually, this is more generic than that one. That is specialised to the concept of "non-empty" and this is a monadic `findFirst` function. I'm alright with marking this as a duplicate if neither exist in the standard library. I thought that this might -- because it is more general. – Saurabh Nanda Jan 18 '20 at 15:02
  • I see. FWIW, the function doesn't compile as listed, but if I omit the type declaration, the code has the inferred type `(a -> Bool) -> t (m a) -> m (Maybe a)`. Neither that nor the type in the OP produces any hits on [Hoogle](https://hoogle.haskell.org). – Mark Seemann Jan 18 '20 at 15:55
  • In situations like this I tend to jump directly to a streaming library like "streaming". If we `import qualified Streaming.Prelude as S`, the function can be defined like `\p -> S.head_ . S.dropWhile (not . p) . S.sequence . S.each`. Not that different from working with normal lists, and doesn't perform unnecessary effects. http://hackage.haskell.org/package/streaming-0.2.3.0/docs/Streaming-Prelude.html#v:head_ http://hackage.haskell.org/package/streaming-0.2.3.0/docs/Streaming-Prelude.html#v:each http://hackage.haskell.org/package/streaming-0.2.3.0/docs/Streaming-Prelude.html#v:sequence – danidiaz Jan 18 '20 at 17:02
  • [related](http://hackage.haskell.org/package/monad-loops-0.4.3/docs/Control-Monad-Loops.html#v:firstM) – Daniel Wagner Jan 18 '20 at 19:33
  • @DanielWagner thanks for that link. Is that a stable/optimized library? Are you using that in production, by any chance? – Saurabh Nanda Jan 19 '20 at 10:16
  • @DanielWagner would you like to add `firstM` as an answer to this? I don't think there is anything in `base` or widely used "almost standard" library to do this. And `firstM` is the exact thing that I need. The only downside is that it is the first time I'm hearing about the `monad-loops` library. – Saurabh Nanda Jan 20 '20 at 07:02

0 Answers0