未能产生懒惰的溪流

Mag*_*ist 2 haskell

我将尽可能简短地说明这个问题.

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

return . take 3 =<< sequence (repeat getChar)
Run Code Online (Sandbox Code Playgroud)

编辑:

我应该补充一点,我试图将选择与生成分开,因此希望产生一个我选择的无限字符流.

sha*_*ang 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)
Run Code Online (Sandbox Code Playgroud)

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

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

  • 在这种情况下,你的"流"是什么意思?如果从带有`readFile`的文件或使用`hGetContents`的句柄读取数据,则流会自动延迟,因为上述函数在内部使用`unsafeInterleaveIO`.但是,由于各种原因,懒惰的I/O被认为是有问题的,因此目前推荐的用于分离生成和选择的解决方案是使用诸如[enumerator](http://hackage.haskell.org/package/enumerator)之类的库,[管道](http://hackage.haskell.org/package/pipes)或[管道](http://hackage.haskell.org/package/conduit). (2认同)

dav*_*420 6

  1. 效果的正确=<<完整效果左侧前=<<开始.
    • 这意味着如果右边的=<<动作将永远运行,那么整个动作将永远运行.
  2. sequence 获取操作列表并返回执行所有这些操作的操作.
    • 如果你给出sequence一个无限的动作列表,它将永远运行.
  3. repeat 获取一个值,并给出该值的无限列表,重复.

你现在看到为什么你会得到你所经历的行为?


这可行,因为没有无限的列表:

sequence (take 3 $ repeat getChar)
Run Code Online (Sandbox Code Playgroud)

但可能你的真正选择功能比"前三个"更复杂.它是什么?