我有以下代码:
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
最佳方式的双重用途?
答案 0 :(得分:4)
在Hayoo上搜索partitionM
将返回至少2个实现该功能的库。这意味着您可以依赖它们或研究它们的来源。
这是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)
关于如何将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])