您将无法将 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)
从/tmp
This 中获取我们两个折叠所需的所有信息,因此我们的组合折叠将需要。
接下来我们可能会编写一个辅助折叠,将 的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