Vous ne pourrez pas diviser un Shell
en deux shells séparés qui s'exécuteront simultanément, sauf s'il y a de la magie que je ne connais pas. Mais l'écriture de fichier est un fold sur le contenu d'un shell ou d'une autre succession de choses. Il est construit en turtle
que vous pouvez toujours combiner de nombreux plis et de les faire en utilisant simultanément le exécuter matériel Control.Foldl
- ici
foldIO :: Shell a -> FoldM IO a r -> IO r -- specializing
Un obus est secrètement un FoldM IO a r -> IO r
sous le capot de toute façon, c'est donc essentiellement runShell
. Pour ce faire, nous devons obtenir le droit Shell
et le droit combiné FoldM IO
. L'idée des types Fold a b
et FoldM m a b
du package foldl
est le pliage simultané.
Je pense que la meilleure façon d'obtenir la coquille droite est juste pour le retour lstree
fois un FilePath
ensemble avec le résultat de testdir
. Vous avez écrit essentiellement ceci:
withDirInfo :: FilePath -> Shell (Bool, FilePath)
withDirInfo tmp = do
let lstmp = lstree tmp
path <- lstmp
bool <- liftIO $ testdir path
return (bool, path)
Alors maintenant, nous pouvons obtenir un Shell (Bool, FilePath)
de /tmp
Cela a toutes les informations nos deux plis auront besoin, et donc que notre fois combiné aura besoin.
Ensuite, nous pourrions écrire un pli d'aide qui imprime le composant Text
du FilePath
à une poignée donnée:
sinkFilePaths :: Handle -> FoldM IO FilePath()
sinkFilePaths handle = L.sink (T.hPutStrLn handle . format fp)
Ensuite, nous pouvons utiliser ce Handle -> FoldM IO FilePath()
pour définir deux FoldM IO (Bool, FilePath)()
. Chacun écrira des choses différentes à différentes poignées, et nous pouvons les unir en un seul pli simultané avec <*
. Ceci est un FoldM IO ...
indépendant et peut être appliqué par ex. à une liste pure de type [(Bool, FilePath)]
en utilisant L.fold
et il va écrire des choses différentes de la liste aux différentes poignées. Dans notre cas, cependant, nous l'appliquerons au Shell (Bool, FilePath)
que nous avons défini.La seule partie subtile de ceci est l'utilisation de L.handlesM
pour imprimer seulement le deuxième élément, dans les deux cas, et seulement ceux filtrés comme des répertoires dans l'autre. Ceci utilise l'objectif _2
et filtered
des bibliothèques d'objectifs. Cela pourrait probablement être simplifiée, mais voir ce que vous pensez:
{-#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
Ok, ça explique très bien comment le faire. La partie qui me manquait était de comprendre que l'écriture dans un fichier peut aussi être un pli utilisant 'L.sink'. Juste signifie que je dois explorer plus la puissance de Foldl! –