如何在 Scalaz7 Iteratees 中使用 IO 而不溢出堆栈?

2023-11-26

考虑这段代码(取自here并修改为使用字节而不是字符行)。

import java.io.{ File, InputStream, BufferedInputStream, FileInputStream }
import scalaz._, Scalaz._, effect._, iteratee.{ Iteratee => I, _ }
import std.list._

object IterateeIOExample {
  type ErrorOr[+A] = EitherT[IO, Throwable, A]

  def openStream(f: File) = IO(new BufferedInputStream(new FileInputStream(f)))
  def readByte(s: InputStream) = IO(Some(s.read()).filter(_ != -1))
  def closeStream(s: InputStream) = IO(s.close())

  def tryIO[A, B](action: IO[B]) = I.iterateeT[A, ErrorOr, B] {
    EitherT(action.catchLeft).map(r => I.sdone(r, I.emptyInput))
  }

  def enumBuffered(r: => BufferedInputStream) = new EnumeratorT[Int, ErrorOr] {
    lazy val reader = r
    def apply[A] = (s: StepT[Int, ErrorOr, A]) => s.mapCont(k =>
      tryIO(readByte(reader)) flatMap {
        case None => s.pointI
        case Some(byte) => k(I.elInput(byte)) >>== apply[A]
      })
  }

  def enumFile(f: File) = new EnumeratorT[Int, ErrorOr] {
    def apply[A] = (s: StepT[Int, ErrorOr, A]) =>
      tryIO(openStream(f)).flatMap(stream => I.iterateeT[Int, ErrorOr, A](
        EitherT(
          enumBuffered(stream).apply(s).value.run.ensuring(closeStream(stream)))))
  }

  def main(args: Array[String]) {
    val action = (
      I.consume[Int, ErrorOr, List] &=
      enumFile(new File(args(0)))).run.run
    println(action.unsafePerformIO())
  }
}

在大小合适的文件 (8kb) 上运行此代码会产生 StackOverflowException。一些搜索发现,可以通过使用 Trampoline monad 而不是 IO 来避免异常,但这似乎不是一个很好的解决方案 - 牺牲功能纯度来让程序完全完成。解决这个问题的明显方法是使用 IO 或 Trampoline 作为 Monad Transformer 来包装另一个,但我找不到它们中任何一个的 Transformer 版本的实现,而且我还没有足够的功能编程大师来解决这个问题。知道如何编写我自己的(更多地了解 FP 是这个项目的目的之一,但我怀疑创建新的 monad 变压器目前有点高于我的水平)。我想我可以围绕创建、运行和返回迭代结果进行一个大的 IO 操作,但这感觉更像是一种解决方法,而不是解决方案。

大概有些 monad 无法转换为 monad 转换器,所以我想知道是否可以在不丢失 IO 或溢出堆栈的情况下处理大文件,如果可以,如何实现?

额外问题:除了让它返回 Either 之外,我想不出任何方法可以让 iteratee 发出它在处理时遇到错误的信号,这使得组合它们变得不那么容易。上面的代码展示了如何使用 EitherT 来处理枚举器中的错误,但是这对于迭代器来说是如何工作的呢?


在创建异常并在代码的各个位置打印它们的堆栈长度之后,我觉得your代码没有溢出。一切似乎都以恒定的堆栈大小运行。所以我寻找其他地方。最终我复制了实现consume并添加了一些堆栈深度打印并确认它在那里溢出。

所以这会溢出:

(I.consume[Int, Id, List] &= EnumeratorT.enumStream(Stream.fill(10000)(1))).run

But,然后我发现这不是:

(I.putStrTo[Int](System.out) &= EnumeratorT.enumStream(Stream.fill(10000)(1)))
  .run.unsafePerformIO()

putStrTo uses foldM并且以某种方式不会导致溢出。所以我想知道是否consume可以实施为foldM。我只是从 Consumer 中复制了一些内容并进行了调整,直到编译完成:

def consume1[E, F[_]:Monad, A[_]:PlusEmpty:Applicative]: IterateeT[E, F, A[E]] = {
  I.foldM[E, F, A[E]](PlusEmpty[A].empty){ (acc: A[E], e: E) =>
    (Applicative[A].point(e) <+> acc).point[F]
  }
}

它成功了!打印一长串整数。

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

如何在 Scalaz7 Iteratees 中使用 IO 而不溢出堆栈? 的相关文章

随机推荐

  • 如何添加触发翻译的谷歌翻译链接?

    我有一个保加利亚语网页 我希望我的用户能够将其一键翻译成英语 此外 当用户进入页面时 页面顶部不应有任何翻译横幅 在用户单击翻译链接后可以 我尝试过使用 googtrans bg en doc 但它不起作用 而且由于以下代码 它还在页面顶部
  • rxjs中如何做链序列

    我想要这样的事情 this myService doSomething subscribe result gt doSomething then gt dosthelse then gt dosanotherthing 所以我想链接 the
  • CSS 重新居中换行元素

    我以为这很简单 但事实证明有点令人头疼 当用户调整浏览器大小并导致其中一个 或多个 换行到下一行时 我试图让图像网格重新居中 我尝试过给网格包装器 display inline block 它的父级值为 text align center
  • 如何在“Java Swing”中获取鼠标悬停事件

    我有一个JPanel其中有多个组件 就像一些JLabels JTextBoxes JComboBoxes JCheckBoxes etc 如果用户将鼠标悬停在这些组件上 3 秒 我想显示一个弹出帮助窗口 到目前为止我添加了一个MouseLi
  • Azure 访问令牌 - Jwt.io 中的签名无效

    这真是一场噩梦 我在使用 jwt io 验证 Azure 访问令牌签名时遇到问题 不管我做什么 答案总是无效的签名 有人可以尝试帮忙解决这个问题吗 我的步骤 我从 MSAL Java 应用程序示例 msal java webapp samp
  • 如何查找或插入 Vec [重复]

    这个问题在这里已经有答案了 我正在尝试编写一个函数 该函数查找返回对 Vec 中现有元素的可变引用 或者如果不存在则将其插入并返回对新元素的可变引用 我已经尝试过几次 但借用检查员不相信 我已将尝试编写的代码简化为下面的示例 该示例给出了相
  • Maven 正在尝试从 maven.ocean.net.au 更新 glassfish 插件

    我们无法部署我们的应用程序 因为 Maven 正在尝试从 maven ocean net au 存储库更新 glassfish 插件 尽管我们的 pom 中没有定义这样的存储库 问题是 maven ocean net au 不在线 因此我们
  • 合并两个 SQLite 数据库文件 (C# .NET)

    我将 C NET 与 SQLite 的 C 包装器一起使用 我正在尝试将两个 SQLite 数据库合并在一起 同时排除重复项 我发现了这个 这是从几个不同的论坛问题中引用的 http old nabble com Attempting to
  • 如果函数声明了返回类型,mypy 是否仅对函数进行类型检查?

    以下文件 from typing import List class A def init self myStr self chars List int list myStr def toString self return join se
  • 使用 ant 或 maven 执行我的 groovy 脚本

    我有以下内容 1个java类 1 个bat 文件 启动groovy 脚本 1 个常规文件 全部在同一个文件夹中 现在我想使用 Maven 或 Ant 来运行 groovy 文件 但我无法让它工作 有人可以告诉我如何编写这个 pom xml
  • 使用 ArrayWritable 进行序列化似乎以一种有趣的方式工作

    我正在与ArrayWritable 在某些时候我需要检查 Hadoop 如何序列化ArrayWritable 这是我通过设置得到的job setNumReduceTasks 0 0 IntArrayWritable 10f11b8 3 In
  • 由于 LARGEADDRESSAWARE 检测指针算术

    我想将我的应用程序切换到LARGEADDRESSAWARE 需要注意的问题之一是指针算术 因为指针差异不再可以表示为有符号 32b 有没有办法在大型 C 项目中自动查找指针减法的所有实例 如果没有 是否有一些 最省力 的手动或半自动方法如何
  • Java Deprecated API 和 SuppressWarnings“弃用” - 实用方法

    我见过很多例子使用DeprecatedAPI 上的注释以便将它们标记为 需要尽快更换 然而 在几乎所有这些情况下 代码开发人员不仅继续使用已弃用的 API 而且还继续使用已弃用的 API 抑制了弃用警告 API 开发人员的最佳意图似乎最终会
  • Xcode 9 UITextView 链接不再可点击

    在 Xcode 9 和 iOS 11 之前 我有一个UITextView在一个UITableViewCell包含多个链接 每个链接都按预期工作 但是自从升级到 iOS 11 和 Xcode 9 后 这些链接不再工作 UITextView 似
  • WebStorm:新的 AngularCli 项目:错误:目录应与格式“路径”匹配

    当我尝试创建一个新的角度 Cli项目 收到此消息 在Run窗口 执行后几秒钟后ng new angularcli dir IDE命令 C Program Files nodejs node exe C Users I AppData Roa
  • Python 3 中的 flatMap 还是 Bind?

    Python 提供了提供映射 过滤器类型功能的列表推导式 我可以用它来做 flatMap 又名绑定操作吗 我见过使用 itertools 或其他附加库的解决方案 我可以用核心 Python 来做到这一点吗 this x 10 x for x
  • 如何?在 ASP.NET 中加密和解密用户成员身份密码

    我们正在使用 ASP NET 会员提供程序创建一个新站点 用于用户注册和登录 我们的旧系统对用户密码进行了加密 以便我们可以在需要时恢复它们 我在弄清楚是否可以使用 ASP NET 成员函数在用户注册时简单地加密密码然后解密以便我可以看到它
  • 如何通过setsid获取执行进程的ID

    我计划通过网络应用程序控制一些程序 如媒体播放器和外壳 由于每次用户访问网页时网页都会死掉 我决定网络应用程序将使用以下命令打开程序setsid然后Web应用程序将通过管道与其进行通信 注意 我不能使用nohup因为像nohup bash
  • 使地图缩放到用户位置和注释(swift 2)

    我正在使用mapkit 我希望地图缩放以显示用户的位置和注释点 而不是仅仅缩放到用户的当前位置 目前我有 let annotation MKPointAnnotation annotation coordinate CLLocationCo
  • 如何在 Scalaz7 Iteratees 中使用 IO 而不溢出堆栈?

    考虑这段代码 取自here并修改为使用字节而不是字符行 import java io File InputStream BufferedInputStream FileInputStream import scalaz Scalaz eff