管道教程:ListT示例

时间:2017-05-15 21:35:47

标签: haskell haskell-pipes

我试图理解pipes tutorial关于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)

如果运行上面的示例,我们得到如下输出:

>>> 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>
>>> 

似乎:

  1. 当你运行它(在ghci上)时,你输入的第一个名字将被绑定,只有第二个名称会改变。我希望两个生产者(由Select input定义)在读取输入时轮流(可能是非确定性的)。
  2. 一次输入quit将允许重新绑定名字。同样,我不明白为什么firstName将绑定到用户输入的第一个值。
  3. 连续两次输入quit将终止该程序。但是,我希望只需要输入quit两次才能退出程序(可能与其他输入交替)。
  4. 我遗漏了上述例子的工作原理,但我看不清楚。

2 个答案:

答案 0 :(得分:9)

  

当你运行它(在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)
  

输入退出一次将允许重新绑定第一个名称。再一次,我   无法理解为什么firstName将绑定到输入的第一个值   用户。

如果我们正在阅读姓氏并遇到退出命令,那么“分支”终止,我们回到上面的级别,从列表中读取另一个名字。只有在使用名字后才能重新创建读取姓氏的“有效列表”。

  

连续两次输入quit将终止该程序。但是,我   我希望只需输入两次quit即可退出   程序(可能与其他输入交替)。

请注意,在最开始输入一个退出也将终止该程序,因为我们正在“关闭”顶级名字列表。

基本上,每次输入quit时,您都会关闭当前分支并上升到“搜索树”中的某个级别。每次输入名字时,你都会进入一个级别。

答案 1 :(得分:0)

要添加@ danidiaz的最佳答案,可以再次提示name提示firstName,而不是仅仅继续询问{ {1}}秒。

您可以做的是使用lastName的{​​{1}}实例,尤其是

MonadZip

因此,您可以将Monad m => ListT m定义为

mzip :: Monad m => ListT m a -> ListT m b -> ListT m (a, b).

你得到了交替的行为。

除此之外,您还可以使用namename :: ListT IO String name = do (firstName, lastName) <- mzip (Select input) (Select input) return (firstName ++ " " ++ lastName) 扩展程序。使用这些,MonadComprehensions的两个版本变为

ParallelListComp