我会尽量简短而切题地说明这个问题。
我希望在向命令行输入三个字符后完成此计算。但是,事实并非如此。我很好奇为什么会这样。
return . take 3 =<< sequence (repeat getChar)
编辑:
我应该补充一点,我正在尝试将选择与生成分开,因此希望生成我从中选择的无限的字符流。
我会尽量简短而切题地说明这个问题。
我希望在向命令行输入三个字符后完成此计算。但是,事实并非如此。我很好奇为什么会这样。
return . take 3 =<< sequence (repeat getChar)
编辑:
我应该补充一点,我正在尝试将选择与生成分开,因此希望生成我从中选择的无限的字符流。
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 有什么不好的地方?”)。
=<<
在开始左侧的效果之前完成右侧的效果=<<
。
=<<
动作将永远运行,那么整个动作将永远运行。sequence
获取一个动作列表并返回一个执行所有这些动作的动作。
sequence
无限的操作列表,它将永远运行。repeat
接受一个值,并给出该值的无限列表,重复。你现在明白为什么你会得到你所经历的行为吗?
这会起作用,因为没有无限列表:
sequence (take 3 $ repeat getChar)
但想必你真正的选择功能比“取前三个”要复杂。它是什么?