Can the section be applied to `a & # 8594; IO Bool`?

I have the following code:

import System.Directory
import System.FilePath
import Control.Monad (filterM)

filesAndDirs dir = do
  entries <- getDirectoryContents dir
  let filtered = [dir </> e | e <- entries, e `notElem` [".", ".."]]
  files <- filterM doesFileExist filtered 
  dirs <- filterM doesDirectoryExist filtered 
  return (files, dirs)

What I would like to write is something like return $ partitionM doesFileExist filtered. Is there a way to reuse or lift partitionor double use in the filterMbest way?

+5
source share
1 answer

A search partitionMon Hayoo will return at least 2 libraries implementing this function. This means that you can either depend on them or study their source.

Here's a more readable translation of this implementation :

partitionM :: (Monad m) => (a -> m Bool) -> [a] -> m ([a], [a])
partitionM p xs = foldM f ([], []) xs
  where 
    f (a, b) x = do
      flag <- p x
      return $ if flag 
        then (x : a, b) 
        else (a, x : b)

As for your question on how to raise a function partitionto partitionM, I came up with the following implementation of a lift function:

liftSplitter :: (Monad m) =>
  ((a -> Bool) -> [a] -> ([a], [a])) -> 
  (a -> m Bool) -> [a] -> m ([a], [a])
liftSplitter splitter kleisliPredicate list = do
  predicateResultsAndItems <- sequence $ do
    item <- list
    return $ do
      predicateResult <- kleisliPredicate item
      return (predicateResult, item)
  return $ results $ predicateResultsAndItems
  where
    results [] = ([], [])
    results ((predicateResult, item) : tail) = (a ++ tailA, b ++ tailB)
      where
        (a, b) = splitter (const predicateResult) [item]
        (tailA, tailB) = results tail

(a -> Bool) -> [a] -> ([a], [a])

(.. partition, break span)

(a -> m Bool) -> [a] -> m ([a], [a])
+4

All Articles