未能产生懒惰的溪流

时间:2012-07-25 12:56:46

标签: haskell

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

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

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

修改

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

2 个答案:

答案 0 :(得分:7)

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

如果您想懒惰地(以及非确定性地)执行I / O,您可以使用System.IO.Unsafe包中的unsafeInterleaveIO函数执行此操作。

实现所需内容的一种方法是,例如,像这样:

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 lazy I/O and closing files""What's so bad about Lazy I/O?")。

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

答案 1 :(得分:6)

  1. =<<左侧的效果开始之前,=<<完成权限的效果开始。
    • 这意味着如果=<<右侧的操作将永久运行,那么整个操作将永远运行。
  2. sequence获取操作列表并返回执行所有这些操作的操作。
    • 如果您为sequence提供无限的操作列表,它将永远运行。
  3. repeat获取一个值,并给出该值的无限列表,重复。
  4. 你现在看到为什么会得到你所经历的行为吗?


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

    sequence (take 3 $ repeat getChar)
    

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