Haskell 中惰性和 I/O 如何协同工作?

2024-02-18

我试图更深入地了解 Haskell 中的惰性。

我今天想象了以下片段:

data Image = Image { name :: String, pixels :: String }

image :: String -> IO Image
image path = Image path <$> readFile path

这里的吸引力在于我可以简单地创建一个 Image 实例并将其传递;如果我需要图像数据,它将被延迟读取 - 如果不需要,则可以避免读取文件的时间和内存成本:

 main = do
   image <- image "file"
   putStrLn $ length $ pixels image

但实际上是这样的吗?惰性如何与 IO 兼容?无论我是否访问都会调用readFilepixels image或者如果我从不引用它,运行时会不会对该 thunk 进行评估?

如果图像确实是延迟读取的,那么 I/O 操作是否可能会无序发生?例如,如果在调用后立即怎么办?image我删除文件?现在 putStrLn 调用在尝试读取时将找不到任何内容。


惰性如何与 I/O 兼容?

简短回答:事实并非如此。


长答案:IO操作是严格按顺序进行的,其原因几乎与您所想到的一样。当然,任何对结果进行的纯计算都可能是惰性的;例如,如果您读入文件,进行一些处理,然后打印出一些结果,则可能不会评估输出不需要的任何处理。但是,整个文件都会被读取,甚至是您从未使用过的部分。如果您想要惰性 I/O,大约有两种选择:

  • 滚动您自己的显式延迟加载例程等,就像使用任何严格的语言一样。看起来很烦人,这是理所当然的,但另一方面,Haskell 是一种很好的、​​严格的、命令式的语言。如果您想尝试一些新的有趣的东西,请尝试查看迭代者 http://okmij.org/ftp/Streams.html.

  • 像一个作弊的骗子一样作弊。功能such as hGetContents http://www.haskell.org/ghc/docs/6.12.2/html/libraries/base-4.2.0.1/System-IO.html#v%3AhGetContents将为您执行惰性的、按需的 I/O,不问任何问题。有什么问题吗?它(从技术上讲)破坏了引用透明度。纯代码可能会间接导致副作用,如果您的代码确实很复杂,则可能会发生涉及副作用排序的有趣事情。hGetContents和朋友们都实施了using unsafeInterleaveIO http://www.haskell.org/ghc/docs/6.12.1/html/libraries/base/System-IO-Unsafe.html#v%3AunsafeInterleaveIO,这就是……正如罐头上所说的那样。它远不如使用unsafePerformIO,但请考虑自己受到警告。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Haskell 中惰性和 I/O 如何协同工作? 的相关文章

  • 在 Python 中延迟转置列表

    所以 我有一个延迟生成的可迭代的三元组 我试图弄清楚如何将其转换为 3 个可迭代对象 分别由元组的第一个 第二个和第三个元素组成 然而 我希望这件事能懒惰地完成 所以 举例来说 我希望 1 2 3 4 5 6 7 8 9 将变成 1 4 7
  • 在帖子上生成最近帖子列表时,如何避免依赖循环?

    所以这有效 create archive html do route idRoute compile do posts lt myRecentFirst gitTimes lt lt loadAll posts let archiveCtx
  • Haskell GHC:具有 N 个构造函数的模式匹配的时间复杂度是多少?

    假设我们有以下 Haskell data T T0 T1 T2 TN toInt T gt Int toInt t case t of T0 gt 0 T1 gt 1 T2 gt 2 TN gt N 这里使用什么算法来执行模式匹配 我看到两
  • 镜头中的观看和使用有什么区别?

    有什么区别 view MonadReader s m gt Getting a s a gt m a and use MonadState s m gt Getting a s a gt m a in 控制镜头吸气剂 https hacka
  • 在 Haskell 中,如何将嵌套上下文中的函数“应用”到上下文中的值?

    nestedApply Applicative f Applicative g gt g f a gt b gt f a gt g f b 正如类型所示 如何获得 a gt b 应用于那个a在上下文中f 感谢帮助 这是关注类型很有帮助的情况
  • 在 Haskell 中对单位的组成(例如英寸、美元等)进行建模

    跟进自我之前的一个问题 https stackoverflow com q 73375273 222529 我问如何创建一个可以对单元进行建模的类型 例如Inch 作为 Haskell 中的一种类型 我现在面临的问题是如何对该单元和其他单元
  • 在 Haskell 中为自定义数据类型创建 Read 类型类的实例

    我有一个自定义数据类型Foo Foo a Int b Int 我正在尝试使 Foo 成为 read 的自定义实例 我已经有一个功能了bar String gt Foo我尝试这样做 instance Read Foo a b where re
  • 计算/获取分层数据的“级别”

    好吧 我真的不知道这是否是正确的标题 但我不知道如何称呼它 我的问题是关于我的作业 我现在已经工作了几个小时 主题是 函数式数据结构 我有点陷入困境 我不知道如何继续 所以我需要编写一个具有以下签名的函数 data Heap e t Hea
  • Haskell 真的是纯粹的吗(有任何语言可以处理系统外的输入和输出)吗?

    在谈到函数式编程中的 Monad 后 该功能是否真的使语言变得纯粹 或者它只是黑板数学之外的现实世界中计算机系统推理的另一张 免狱卡 EDIT 这不是有人在这篇文章中所说的火焰诱饵 而是一个真正的问题 我希望有人能用它来击倒我并说 证明 它
  • 算法 - 如何有效删除列表中的重复元素?

    有一个list L 它包含以下元素任意类型each 如何有效删除此类列表中的所有重复元素 必须保留订单 只需要一个算法 因此不允许导入任何外部库 相关问题 在Python中 从列表中删除重复项以使所有元素都是唯一的最快算法是什么在维持秩序的
  • 如何将惰性变量传递给函数参数而不对其求值,除非返回

    这个问题是针对python的 尽管我不介意用户分享其他语言的经验 基本上我的问题是尝试将惰性变量传递给函数 就我而言 我可能无法控制该函数 因此无法更改它以将生成器作为输入 示例 请注意 dict get 是函数的示例 但它很可能是 foo
  • “反向”使用 Maybe Monad

    假设我有很多功能 f a gt Maybe a g a gt Maybe a h a gt Maybe a 我想按以下方式组合它们 如果 f 返回 Nothing 则计算 g 如果 g 返回 Nothing 则计算 h 如果其中任何一个计算
  • 是否有一个基于对象身份的、线程安全的记忆库?

    我知道记忆化似乎是堆栈溢出的 haskell 标签上的一个长期话题 但我think以前没有人问过这个问题 我知道 Haskell 有几个不同的 现成 记忆库 memo combinators 和 memotrie 包 利用涉及惰性无限数据结
  • GHC 是否使用存在类型的动态调度?

    下面的代码是否使用了 C 或 Java 中所理解的动态调度 据我了解 在最后一行 编译器不可能在编译时知道要调用哪个 实现 但代码会编译并产生正确的结果 有人可以解释一下 这背后有什么样的实现 例如 vptr 吗 LANGUAGE Exis
  • 处理许多不相关的类型时避免样板

    我正在编写处理以下值的代码语言 扩展 注释 语法 http hackage haskell org packages archive haskell src exts 1 1 4 doc html Language Haskell Exts
  • Haskell 测量函数性能

    在 Haskell 中 我如何 简单地 测量函数的性能 例如 运行需要多长时间 或者需要多少内存 我知道分析 但是 是否有一种更简单的方法不需要我对代码进行太多更改 测量运行需要多长时间以及需要多少内存是两个独立的问题 即 基准测试和分析
  • 如何组合过滤条件

    过滤器类函数接受一个条件 a gt Bool 并在过滤时应用它 当您有多个条件时 使用过滤器的最佳方法是什么 使用了应用函数 liftA2 而不是 liftM2 因为出于某种原因我不明白 liftM2 在纯代码中如何工作 liftM2 组合
  • 什么是阴谋地狱?

    在阅读有关 阴谋地狱 的内容时 我有点困惑 因为这个词的含义太多了 我猜最初 Cabal Hell 指的是钻石依赖问题 该问题是通过限制构建计划在每个构建计划中只有任何包的单个版本来解决的 一个包的两个不同版本不能存在于单个构建计划中 正如
  • Haskell 和 Idris 之间的区别:类型宇宙中运行时/编译时的反映

    因此 在 Idris 中 编写以下内容是完全有效的 item b Bool gt if b then Nat else List Nat item True 42 item False 1 2 3 cf https www youtube
  • 将名称绑定到值与将值分配给变量

    阅读 Bartosz Milewski 的文章完整的 https www fpcomplete com school starting with haskell basics of haskell 3 pure functions lazi

随机推荐