5

私は次のコードを持っています:

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

4

1 に答える 1

4

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])

(つまり、partitionbreakおよびspan) に

(a -> m Bool) -> [a] -> m ([a], [a])
于 2013-03-05T08:29:10.710 に答える