【问题标题】:Can I be sure of order of IO actions in this example?我可以确定此示例中 IO 操作的顺序吗?
【发布时间】:2014-05-12 22:21:11
【问题描述】:

目前,我在main 及其周围有这段代码:

import Control.Monad
import Control.Applicative

binSearch :: Ord a => [a] -> a -> Maybe Int

main = do
    xs <- lines <$> readFile "Cars1.txt"
    x <- getLine <* putStr "Registration: "  -- Right?
    putStrLn $ case binSearch xs x of
                    Just n -> "Found at position " ++ show n
                    Nothing -> "Not found"

我希望打印“Registration:”,然后程序等待x 的输入。我所写的是否意味着情况会如此?我需要&lt;*,还是将putStr 表达式放在上面的行中也能正常工作?

PS:我知道我必须将 binSearch 转换为使用数组而不是列表(否则可能不值得进行二进制搜索),但这是另一天的问题。

【问题讨论】:

  • 懒惰在这里发挥作用的唯一地方是readFile,这是一种偷偷摸摸的功能——文件将在需要xs时被增量读取。其他一切——一般来说,IO monad 中的所有操作(readFilegetContents 除外,它们被明确写成惰性)将按照您对命令式语言的期望顺序执行。

标签: haskell io lazy-evaluation


【解决方案1】:

线

x <- getLine <* putStr "Registration: "

从左到右对 IO 操作进行排序:首先将一行作为输入,然后打印消息,最后将变量 x 绑定到 getLine 的结果。

我需要

如果你想让消息在输入之前,你必须把putStr放在上面一行,如下:

main :: IO ()
main = do
    xs <- lines <$> readFile "Cars1.txt"
    putStr "Registration: "
    x <- getLine
    putStrLn $ case binSearch xs x of
                    Just n  -> "Found at position " ++ show n
                    Nothing -> "Not found"

或者,

    x <- putStr "Registration: " *> getLine

    x <- putStr "Registration: " >> getLine

可以,但它们的可读性较差。

最后,既然你添加了 lazy-evaluation 标签,让我补充一下,你的问题实际上不是关于懒惰,而是关于如何定义运算符 &lt;*,特别是关于顺序它在其中对 IO 操作进行排序。

【讨论】:

  • 是的,我对&lt;* 有点困惑,我会发现单独的一行更容易阅读。
  • 那么语句的顺序很重要吗?我记得以前做过类似的事情,只是随机动作。
  • @JamesWood 是的,所有 Applicative 运算符 &lt;$&gt;,&lt;*&gt;,&lt;*,... 从左到右顺序排列 IO 操作。 liftM,liftM2,... 也是如此。 do 中的操作也遵循此顺序。我唯一记得的从右到左排序操作的运算符是&lt;&lt;=&lt;&lt;,它们是flipped 的变体&gt;&gt;,&gt;&gt;=
猜你喜欢
  • 1970-01-01
  • 2018-07-24
  • 2011-05-03
  • 2019-04-03
  • 2011-10-05
  • 2014-03-14
  • 2013-12-26
  • 2010-10-29
  • 1970-01-01
相关资源
最近更新 更多