我有以下代码:
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)
我想写的是return $ partitionM doesFileExist filtered
。是否有一种方法可以重复使用或提升partition
或双重使用filterM
是最好的方法?
在Hayoo上搜索partitionM
将返回至少2个实现该函数的库。这意味着你可以依赖它们,也可以研究它们的来源。
下面是这个实现的更可读的翻译:
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)
关于如何将partition
函数提升到partitionM
的问题,我提出了以下提升函数的实现:
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])