您将无法将 a 拆分Shell为同时运行的两个单独的 shell,除非有一些我不知道的魔法。但是文件写入是对 shell 内容或其他一系列事物的折叠。它内置于turtle其中,您始终可以组合许多折叠并使用该Control.Foldl材料使它们同时运行 - 这里
foldIO :: Shell a -> FoldM IO a r -> IO r -- specializing
无论如何,外壳都是秘密的FoldM IO a r -> IO r,所以这基本上是runShell. 要做到这一点,我们需要把正确的Shell和正确的结合起来FoldM IO。Fold a b包装中的和FoldM m a b类型的整个想法foldl是同时折叠。
我认为获得正确外壳的最简单方法就是让lstree折叠返回 aFilePath 和. testdir你基本上是这样写的:
withDirInfo :: FilePath -> Shell (Bool, FilePath)
withDirInfo tmp = do
let lstmp = lstree tmp
path <- lstmp
bool <- liftIO $ testdir path
return (bool, path)
所以现在我们可以Shell (Bool, FilePath)从/tmpThis 中获取我们两个折叠所需的所有信息,因此我们的组合折叠将需要。
接下来我们可能会编写一个辅助折叠,将 的Text组件打印FilePath到给定的句柄:
sinkFilePaths :: Handle -> FoldM IO FilePath ()
sinkFilePaths handle = L.sink (T.hPutStrLn handle . format fp)
然后我们可以用它Handle -> FoldM IO FilePath ()来定义两个FoldM IO (Bool, FilePath) (). 每个都会将不同的内容写入不同的句柄,我们可以将它们合并为一个同时折叠的<*. 这是一个独立的FoldM IO ...,例如可以应用于类型的纯列表[(Bool, FilePath)]usingL.fold并且它将从列表中写入不同的东西到不同的句柄。但是,在我们的例子中,我们会将其应用于Shell (Bool, FilePath)我们定义的。
唯一微妙的部分是使用L.handlesM仅打印第二个元素,在这两种情况下,并且仅在另一种情况下过滤为目录的那些。这使用_2镜头和filtered镜头库。这可能会被简化,但看看你的想法:
{-#LANGUAGE OverloadedStrings #-}
import Turtle
import qualified Control.Foldl as L
import qualified System.IO as IO
import Control.Lens (_2,filtered)
import qualified Data.Text.IO as T
main = IO.withFile "tmpfiles.txt" IO.WriteMode $ \h ->
IO.withFile "tmpdirs.txt" IO.WriteMode $ \h' -> do
foldIO (withDirInfo "/tmp") (sinkFilesDirs h h')
withDirInfo :: Turtle.FilePath -> Shell (Bool, Turtle.FilePath)
withDirInfo tmp = do
let lstmp = lstree tmp
path <- lstmp
bool <- liftIO $ testdir path
return (bool, path)
sinkFilePaths :: Handle -> FoldM IO Turtle.FilePath ()
sinkFilePaths handle = L.sink (T.hPutStrLn handle . format fp)
sinkFilesDirs :: Handle -> Handle -> FoldM IO (Bool, Turtle.FilePath) ()
sinkFilesDirs h h' = allfiles <* alldirs where
allfiles :: L.FoldM IO (Bool, Turtle.FilePath) ()
allfiles = L.handlesM _2 (sinkFilePaths h)
-- handle the second element of pairs with sinkFilePaths
alldirs :: FoldM IO (Bool, Turtle.FilePath) ()
alldirs = L.handlesM (filtered (\(bool,file) -> bool) . _2) (sinkFilePaths h')
-- handle the second element of pairs where the first element
-- is true using sinkFilePaths