这是你如何做到这一点的pipes
方式。我真的不知道你是如何实现loadMeta
andfind
的,所以我只是编造了一些东西:
import Pipes
find :: Producer FilePath IO ()
find = each ["heavy.mp3", "metal.mp3"]
type MetaData = String
loadMeta :: String -> IO MetaData
loadMeta file = return $ "This song is " ++ takeWhile (/= '.') file
loadMetaList :: Pipe FilePath MetaData IO r
loadMetaList = mapM loadMeta
要运行它,我们只需像管道一样组合处理阶段并使用以下命令运行管道runEffect
:
>>> runEffect $ find >-> loadMetaList >-> stdoutLn
This song is heavy
This song is metal
有几个关键点需要指出:
例如,即使我们使用无限的文件列表,它也可以工作:
>>> import qualified Pipes.Prelude as Pipes
>>> runEffect $ each (cycle ["heavy.mp3", "metal.mp3"]) >-> loadMetaList >-> Pipes.stdoutLn
This song is heavy
This song is metal
This song is heavy
This song is metal
This song is heavy
This song is metal
...
- 它只会根据需要进行计算。如果我们指定我们只想要三个结果,即使我们提供无限的文件列表,它也会执行返回两个结果所需的最小加载量。
例如,我们可以使用以下方法限制结果数量take
:
>>> runEffect $ each (cycle ["heavy.mp3", "metal.mp3"]) >-> loadMetaList >-> Pipes.take 3 >-> Pipes.stdoutLn
This song is heavy
This song is metal
This song is heavy
所以你问有什么问题unsafeInterleaveIO
。的主要限制unsafeInterleaveIO
是您无法保证IO
操作实际发生的时间,这会导致以下常见陷阱:
Handle
s 在文件被读取之前被意外关闭
IO
迟到或从不发生的行动
纯代码有副作用和抛出IOException
s
Haskell 的IO
系统相对于其他语言的最大优势在于,Haskell 将评估模型与副作用的顺序完全解耦。当你使用 lazyIO
时,你失去了这种解耦,然后副作用的顺序与 Haskell 的评估模型紧密结合,这是一个巨大的倒退。
这就是为什么使用惰性通常是不明智的IO
,尤其是现在有简单而优雅的替代方案。
如果你想了解更多关于如何使用pipes
来安全地实现惰性IO
,那么你可以阅读大量的管道教程。