Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can partition be applied to `a -> IO Bool`?

Tags:

haskell

monads

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 partition or is the double use of filterM the best way?

like image 343
huynhjl Avatar asked Oct 04 '22 20:10

huynhjl


1 Answers

A search for partitionM on Hayoo will return you at least 2 libraries implementing that 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)

Concerning your question on how to lift the partition function to partitionM, I came up with the following implementation of a lifting 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

You can use this function to lift all functions of type

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

(i.e., partition, break and span) to

(a -> m Bool) -> [a] -> m ([a], [a])
like image 120
Nikita Volkov Avatar answered Oct 11 '22 08:10

Nikita Volkov