Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/typo3/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell 从非IO列表创建惰性IO列表_Haskell_File Io_Lazy Loading_Lazy Evaluation_Lazy Sequences - Fatal编程技术网

Haskell 从非IO列表创建惰性IO列表

Haskell 从非IO列表创建惰性IO列表,haskell,file-io,lazy-loading,lazy-evaluation,lazy-sequences,Haskell,File Io,Lazy Loading,Lazy Evaluation,Lazy Sequences,我有一个由创建的文件名惰性列表。我也希望能够惰性地加载这些文件的元数据。这意味着,如果我从元数据中获取10个元素,它应该只搜索这10个文件的元数据。事实上,find完美地为您提供了10个文件,如果您在不挂盘的情况下请求它们,而我的脚本会搜索所有文件的元数据 main = do files <- find always always / metadata <- loadMetaList files loadMetaList :: [String] -> IO

我有一个由创建的文件名惰性列表。我也希望能够惰性地加载这些文件的元数据。这意味着,如果我从
元数据
中获取10个
元素,它应该只搜索这10个文件的元数据。事实上,
find
完美地为您提供了10个文件,如果您在不挂盘的情况下请求它们,而我的脚本会搜索所有文件的元数据

main = do
    files <- find always always / 
    metadata <- loadMetaList files

loadMetaList :: [String] -> IO [Metadata]
loadMetaList file:files = do
    first <- loadMeta file
    rest <- loadMetaList files
    return (first:rest)

loadMeta :: String -> IO Metadata
main=do
文件IO的
(>>=)
单子的
(>>=)

loadMetaList :: [String] -> IO [Metadata]
loadMetaList file:files = do
    first <- loadMeta file
    rest <- loadMetaList files
    return (first:rest)
使用(该
find
也使用)。这样,在需要其结果之前不会执行
loadMetaList files
,如果只需要10个文件的元数据,则只会加载该文件


它不像它的表亲unsafePerformIO那样不安全,但也应该小心处理。

以下是使用管道的方法。我真的不知道如何实现
loadMeta
find
,所以我只是编了一些东西:

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
有几点需要指出:

  • 您可以将
    find
    设置为
    Producer
    ,这样它也只能懒洋洋地搜索目录树。我知道您不需要此功能,因为您的文件集现在很小,但当您的目录变大时,很容易在以后包含此功能

  • 它是懒惰的,但没有
    不愉快的交互。它立即生成每个输出,不必等待首先收集整个结果列表

例如,即使我们使用无限的文件列表,它也会起作用:

>>> 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
的主要限制是您无法保证
IO
操作实际发生的时间,这导致以下常见陷阱:

  • 句柄
    s在读取文件之前意外关闭

  • IO
    晚发生或从不发生的操作

  • 纯代码有副作用并引发
    IOException
    s

Haskell的
IO
系统相对于其他语言的最大优势在于,Haskell将评估模型与副作用顺序完全解耦。当您使用lazy
IO
时,您将失去这种解耦,然后副作用的顺序将与Haskell的评估模型紧密结合,这是一个巨大的倒退

这就是为什么使用lazy
IO
通常是不明智的,尤其是现在有了简单而优雅的替代方案


如果您想了解更多关于如何使用
管道
安全地实现惰性
IO
,那么您可以阅读详细信息。

这是or的一个很好的使用案例。起初我认为它是“loadMetalList”,就像在一堆重金属MP3中一样事实上,它是用于加载MP3的元数据为什么不只是loadMetalList:[字符串]->[IO元数据]?然后在需要时单独评估它们?这是一个过于简化的实际实现示例。loadMetaList可能会丢弃一些文件,具体取决于它们的元数据(例如类型)。请问unsafeInterleaveIO何时“不安全”?为什么在我的情况下它是安全的?在你的情况下它不一定是安全的。但是既然
find
已经使用了它,放入
loadMetaList
并不会增加不安全性,所以这里不需要太担心。
unsafeInterleaveIO
会延迟其参数的执行,因此a)你失去了其顺序的可预测性事情完成后,b)文件可以在延迟执行的同时进行更改,因此您可能会得到与未执行时不同的结果;c)文件打开的时间可能比预期的长,从而导致文件句柄耗尽;d)我确信还有其他潜在问题。但在a)不重要,b)和c)已知的情况下这不是问题,它简化了很多事情。从我有限的经验来看,大多数普通应用程序都属于这一类,但对于那些不属于这一类的应用程序来说,这可能是灾难性的。
>>> 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