Dam*_*les 6 haskell haskell-pipes
我试图弄清楚管道教程中提到的一个例子ListT
:
import Pipes
import qualified Pipes.Prelude as P
input :: Producer String IO ()
input = P.stdinLn >-> P.takeWhile (/= "quit")
name :: ListT IO String
name = do
firstName <- Select input
lastName <- Select input
return (firstName ++ " " ++ lastName)
Run Code Online (Sandbox Code Playgroud)
如果运行上面的示例,我们得到如下输出:
>>> runEffect $ every name >-> P.stdoutLn
Daniel<Enter>
Fischer<Enter>
Daniel Fischer
Wagner<Enter>
Daniel Wagner
quit<Enter>
Donald<Enter>
Stewart<Enter>
Donald Stewart
Duck<Enter>
Donald Duck
quit<Enter>
quit<Enter>
>>>
Run Code Online (Sandbox Code Playgroud)
看起来:
Select input
)在读取输入时轮流(可能是非确定性的).quit
一次将允许重新绑定第一个名称.同样,我没有看到为什么firstName
会绑定到用户输入的第一个值.quit
连续输入两次将终止该程序.但是,我希望quit
只需要输入两次才能退出程序(可能与其他输入交替).我遗漏了上面例子的工作原理,但是我看不清楚.
当你运行它(在GHCi上)时,你输入的第一个名字将被绑定,只有第二个名称会改变.我希望两个生产者(定义为
Select input
)在读取输入时轮流(可能是非确定性的).
ListT
不这样做.相反,它是"深度优先".每次获得名字时,它都会重新开始阅读整个姓氏列表.
该示例不会这样做,但每个姓氏列表可能取决于先前已读取的名字.像这样:
input' :: String -> Producer String IO ()
input' msg =
(forever $ do
liftIO $ putStr msg
r <- liftIO $ getLine
yield r
) >-> P.takeWhile (/= "quit")
name' :: ListT IO String
name' = do
firstName <- Select input
lastName <- Select $ input' $ "Enter a last name for " ++ firstName ++ ": "
return (firstName ++ " " ++ lastName)
Run Code Online (Sandbox Code Playgroud)
输入一次退出将允许重新绑定第一个名称.同样,我不明白为什么firstName将绑定到用户输入的第一个值.
如果我们正在阅读姓氏并遇到退出命令,那么"分支"终止,我们回到上面的级别,从列表中读取另一个名字.只有在使用名字后,才会重新创建读取姓氏的"有效列表".
quit
连续输入两次将终止该程序.但是,我希望quit
只需要输入两次才能退出程序(可能与其他输入交替).
请注意,在最开始输入单个退出也将终止程序,因为我们正在"关闭"顶级名字列表.
基本上,每次进入时,quit
您都会关闭当前分支并在"搜索树"中上升一级.每次输入名字时,您都会进入一个级别.