2

我会尽量简短而切题地说明这个问题。

我希望在向命令行输入三个字符后完成此计算。但是,事实并非如此。我很好奇为什么会这样。

return . take 3 =<< sequence (repeat getChar)

编辑:

我应该补充一点,我正在尝试将选择与生成分开,因此希望生成我从中选择的无限的字符流。

4

2 回答 2

7

I/O 确定性地对动作进行排序,所以你真正的意思是你想要getChar无限次地执行动作,然后在完成之后,你想要从生成的列表中获取前三个项目。您可能会看到这将需要很长时间。

如果您想延迟执行 I/O(并且不确定),您可以使用包中的函数执行此unsafeInterleaveIO操作System.IO.Unsafe

例如,实现您想要的一种方法是:

import System.IO.Unsafe

lazyIOSequence :: [IO a] -> IO [a]
lazyIOSequence [] = return []
lazyIOSequence (x:xs) = do
    first <- unsafeInterleaveIO $ x
    rest  <- unsafeInterleaveIO $ lazyIOSequence xs
    return $ first:rest

test = return . take 3 =<< lazyIOSequence (repeat getChar)

但是,现在用户对数据的实际提示会延迟,直到您评估列表的元素,因此它可能不会像您希望的那样运行。事实上,惰性 I/O 流通常被认为是有问题的(参见例如问题“Haskell 惰性 I/O 和关闭文件”“惰性 I/O 有什么不好的地方?”)。

目前推荐的将生产与选择和处理分开的方法是使用各种严格的流处理库之一,例如枚举器、管道管道

于 2012-07-25T13:13:51.693 回答
6
  1. =<<在开始左侧的效果之前完成右侧的效果=<<
    • 这意味着如果右侧的=<<动作将永远运行,那么整个动作将永远运行。
  2. sequence获取一个动作列表并返回一个执行所有这些动作的动作。
    • 如果您提供sequence无限的操作列表,它将永远运行。
  3. repeat接受一个值,并给出该值的无限列表,重复。

你现在明白为什么你会得到你所经历的行为吗?


这会起作用,因为没有无限列表:

sequence (take 3 $ repeat getChar)

但想必你真正的选择功能比“取前三个”要复杂。它是什么?

于 2012-07-25T13:10:27.157 回答