分区可以应用于"一个 -> IO 布尔值"吗?



我有以下代码:

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, breakspan)

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

最新更新