2010-02-18 46 views
8

我想在哈斯克尔的一个小实验,想知道是否有可能利用懒惰来处理IO。我想编写一个函数,它接受一个String(一个Chars列表),并产生一个字符串,懒洋洋地。然后,我希望能够懒惰地从IO中缓慢地提供它的字符,因此每个字符都会在可用时立即进行处理,并且会在需要的字符可用时生成输出。但是,我不太确定是否/如何从IO单元内的输入中生成一个懒惰列表。Haskell中的“惰性IO”?

+0

请澄清:你需要一个接受一个字符串和“产生”一个字符串---“产生”=“返回”,“输出到文件句柄”的函数,或者是什么?然后你想“懒惰地从IO中提取字符”---这是什么意思? – dave4420 2010-02-18 16:42:25

回答

14

Haskell中的常规字符串IO很懒。所以你的例子应该是开箱即用。

下面是一个例子,使用“交互”功能,它适用的功能字符的懒惰流:

interact :: (String -> String) -> IO() 

让我们从输入流中过滤出字母e,懒惰地(即,运行在不断的空间):

main = interact $ filter (/= 'e') 

你也可以,如果你喜欢用getContents和putStr。他们都很懒。

运行它从字典中筛选字母“E”:

$ ghc -O2 --make A.hs 
$ ./A +RTS -s < /usr/share/dict/words 
... 
       2 MB total memory in use (0 MB lost due to fragmentation) 
... 

,所以我们看到它在一个恒定2M足迹跑了。

+2

你也可以在命令行看到这个效果。在shell/Terminal /运行Don的'A'程序,无论您的操作系统使用什么,并直接输入文本。假设它是行缓冲的,当你在每行之后按回车时,即使程序看起来只是对“过滤器”进行一次“调用”,你仍会立即看到过滤后的文本。 – Nefrubyr 2010-02-19 11:49:10

3
unsafeInterleaveIO :: IO a -> IO a 

unsafeInterleaveIO阿洛斯IO计算被推迟懒洋洋地。当通过IO a类型的值时,IO将仅在要求值a时执行。这用于实现惰性文件读取,请参阅System.IO.hGetContents

例如,main = getContents >>= return . map Data.Char.toUpper >>= putStr是懒惰的;当你向标准输入提供字符时,你会在标准输出中获得字符。

(这是一样的书写main = interact $ map Data.Char.toUpper,为行踪诡秘的回答。)

7

做懒IO的最简单的方法涉及的功能,如interactreadFilehGetContents,而这样,作为穿上说;在书中Real World Haskell中有更多关于这些的讨论,您可能会觉得有用。如果内存服务于我,所有这些功能最终都会使用ephemient提到的unsafeInterleaveIO来实现,所以您也可以按照自己的意愿构建自己的函数。

另一方面,请注意unsafeInterleaveIO正如它在锡罐上所说的那样:不安全的IO可能是明智的。使用它 - 或基于它的功能 - breaks purity and referential transparency。这允许显然是纯粹的功能(即,不返回IO动作)在评估时影响外部世界,从相同的参数产生不同的结果,以及所有其他不愉快的事情。在实践中,使用unsafeInterleaveIO的最明智的方式不会造成问题,而简单的错误通常会导致明显且容易诊断的错误,但是您失去了一些很好的保证。

当然有其他选择;你可以在Hackage上找到提供受限制的,safer lazy IOconceptually different approaches的各种图书馆。但是,鉴于问题在实际使用中很少出现,我认为大多数人倾向于坚持内置的,技术上不安全的功能。