Haskell乌龟-拆分一个shell
Haskell Turtle - split a shell
是否可以在 Turtle 库 (Haskell) 中拆分 Shell 并对 shell 的任一拆分执行不同的操作,以便原始 Shell只有 运行 一次吗?
/---- shell2
---Shell1 --/
\
\-----shell3
比如,怎么做
do
let lstmp = lstree "/tmp"
view lstmp
view $ do
path <- lstmp
x <- liftIO $ testdir path
return x
这样 lstree "/tmp" 只会 运行 一次。
具体来说,我想使用输出将 Shell 2 和 Shell 3 发送到不同的文件。
听起来您正在寻找类似 async
的东西来将您的 shell 从第一个 shell 中分离出来,然后等待它们 return。 async
是一个非常强大的库,它可以实现比下面的示例更多的功能,但它提供了一个非常简单的解决方案来满足您的要求:
import Control.Concurrent.Async
import Turtle.Shell
import Turtle.Prelude
main :: IO ()
main = do
let lstmp1 = lstree "/tmp"
let lstmp2 = lstree "/etc"
view lstmp1
view lstmp2
job1 <- async $ view $ do
path <- lstmp1
x <- liftIO $ testdir path
return x
job2 <- async $ view $ do
path <- lstmp2
x <- liftIO $ testdir path
return x
wait job1
wait job2
这是您要找的吗?
您将无法将 Shell
拆分为两个单独的 shell 同时 运行,除非有一些我不知道的魔法。但是文件写入是 fold 超过 shell 或其他一些连续事物的内容。它内置于 turtle
中,您可以随时组合多个折叠并使用 Control.Foldl
material 同时制作它们 运行 - 这里
foldIO :: Shell a -> FoldM IO a r -> IO r -- specializing
A shell 无论如何都是秘密的 FoldM IO a r -> IO r
,所以这基本上是 runShell
。为此,我们需要获得正确的 Shell
和正确的组合 FoldM IO
。来自 foldl
包的 Fold a b
和 FoldM m a b
类型的整个想法是同时折叠。
我认为获得正确 shell 的最简单方法就是让 lstree
折叠 return 一个 FilePath
在一起 结果为 testdir
。你基本上是这样写的:
withDirInfo :: FilePath -> Shell (Bool, FilePath)
withDirInfo tmp = do
let lstmp = lstree tmp
path <- lstmp
bool <- liftIO $ testdir path
return (bool, path)
所以现在我们可以从 /tmp
得到一个 Shell (Bool, FilePath)
这有我们两个折叠需要的所有信息,因此我们的组合折叠需要。
接下来我们可能会编写一个辅助折叠,将 FilePath
的 Text
组件打印到给定句柄:
sinkFilePaths :: Handle -> FoldM IO FilePath ()
sinkFilePaths handle = L.sink (T.hPutStrLn handle . format fp)
那我们可以用这个Handle -> FoldM IO FilePath ()
定义两个FoldM IO (Bool, FilePath) ()
。每个都会将不同的东西写入不同的句柄,我们可以使用 <*
将它们合并为一个同时折叠。这是一个独立的 FoldM IO ...
,可以应用于例如使用 L.fold
到 [(Bool, FilePath)]
类型的纯列表,它会将列表中的不同内容写入不同的句柄。不过,在我们的例子中,我们会将其应用于我们定义的 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
是否可以在 Turtle 库 (Haskell) 中拆分 Shell 并对 shell 的任一拆分执行不同的操作,以便原始 Shell只有 运行 一次吗?
/---- shell2
---Shell1 --/
\
\-----shell3
比如,怎么做
do
let lstmp = lstree "/tmp"
view lstmp
view $ do
path <- lstmp
x <- liftIO $ testdir path
return x
这样 lstree "/tmp" 只会 运行 一次。
具体来说,我想使用输出将 Shell 2 和 Shell 3 发送到不同的文件。
听起来您正在寻找类似 async
的东西来将您的 shell 从第一个 shell 中分离出来,然后等待它们 return。 async
是一个非常强大的库,它可以实现比下面的示例更多的功能,但它提供了一个非常简单的解决方案来满足您的要求:
import Control.Concurrent.Async
import Turtle.Shell
import Turtle.Prelude
main :: IO ()
main = do
let lstmp1 = lstree "/tmp"
let lstmp2 = lstree "/etc"
view lstmp1
view lstmp2
job1 <- async $ view $ do
path <- lstmp1
x <- liftIO $ testdir path
return x
job2 <- async $ view $ do
path <- lstmp2
x <- liftIO $ testdir path
return x
wait job1
wait job2
这是您要找的吗?
您将无法将 Shell
拆分为两个单独的 shell 同时 运行,除非有一些我不知道的魔法。但是文件写入是 fold 超过 shell 或其他一些连续事物的内容。它内置于 turtle
中,您可以随时组合多个折叠并使用 Control.Foldl
material 同时制作它们 运行 - 这里
foldIO :: Shell a -> FoldM IO a r -> IO r -- specializing
A shell 无论如何都是秘密的 FoldM IO a r -> IO r
,所以这基本上是 runShell
。为此,我们需要获得正确的 Shell
和正确的组合 FoldM IO
。来自 foldl
包的 Fold a b
和 FoldM m a b
类型的整个想法是同时折叠。
我认为获得正确 shell 的最简单方法就是让 lstree
折叠 return 一个 FilePath
在一起 结果为 testdir
。你基本上是这样写的:
withDirInfo :: FilePath -> Shell (Bool, FilePath)
withDirInfo tmp = do
let lstmp = lstree tmp
path <- lstmp
bool <- liftIO $ testdir path
return (bool, path)
所以现在我们可以从 /tmp
得到一个 Shell (Bool, FilePath)
这有我们两个折叠需要的所有信息,因此我们的组合折叠需要。
接下来我们可能会编写一个辅助折叠,将 FilePath
的 Text
组件打印到给定句柄:
sinkFilePaths :: Handle -> FoldM IO FilePath ()
sinkFilePaths handle = L.sink (T.hPutStrLn handle . format fp)
那我们可以用这个Handle -> FoldM IO FilePath ()
定义两个FoldM IO (Bool, FilePath) ()
。每个都会将不同的东西写入不同的句柄,我们可以使用 <*
将它们合并为一个同时折叠。这是一个独立的 FoldM IO ...
,可以应用于例如使用 L.fold
到 [(Bool, FilePath)]
类型的纯列表,它会将列表中的不同内容写入不同的句柄。不过,在我们的例子中,我们会将其应用于我们定义的 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