Purescript 的 Data.Foldable for_ 不是堆栈安全的吗?

如何解决Purescript 的 Data.Foldable for_ 不是堆栈安全的吗?

如果 actions一个适当大的数组,这会造成堆栈溢出:

modifyPerIndex :: forall a. Array (Tuple Int (a -> a)) -> Array a -> Array a
modifyPerIndex actions array = run do
  mutableArray <- thaw array
  for_ actions \(Tuple index action) -> modify index action mutableArray
  pure mutableArray

这不会:

modifyPerIndex :: forall a. Array (Tuple Int (a -> a)) -> Array a -> Array a
modifyPerIndex actions array = run do
  mutableArray <- thaw array
  foreach actions \(Tuple index action) -> void $ modify index action mutableArray
  pure mutableArray

我假设这就是为什么 Control.Monad.ST 有自己的 foreach 版本。 for_applicative & Foldable 是比 foreachArray 宽松得多的约束。话虽如此,我不确定 applicativeFoldable 缺少什么,以至于 for_ 不能是堆栈安全的(或者不能没有其他一些缺点)

我对源代码进行了一些挖掘,并注意到 for_ 是通过 foldr 实现的。我不确定在哪里可以找到 Array 的 foldr 实例。

我对这方面的很多东西都很陌生,只是想扩大我的一般理解。 :)

解决方法

FoldableArray 实例是 here,而 herefoldr 的实际代码。正如你所看到的,它是堆栈安全的,因为它根本不使用堆栈:它只是一个普通的旧 JS 循环,它改变了一个累加器。

最终不是堆栈安全的是traverse_(它是带有翻转参数的for_)。查看the source:看到折叠函数是(*>) f吗?这意味着在某些 traverse_ 上运行 Foldable 的结果将是一系列 *> 调用,如下所示:

traverse_ f [1,2,3,4] == f 1 *> f 2 *> f 3 *> f 4 *> pure unit

此处的关键见解是 f 计算实际上并未在 traverse_ 的执行期间运行。 traverse_ 只是像这样构建一个它们的链,并且只有当你去 bind 它(使用 >>= 或在 do 中)时 - 那就是该链被执行的时候.

当您尝试运行基于 *> 的计算时会发生什么?好吧,*>applySecond 的别名,它本身利用了 <*> - apply 的别名,它是 Apply 的一个方法,其 {{3 }} 使用 instance for ST

ap 的主体绑定了第一个计算,即 f 1 *> f 2 *> f 3 *> f 4,但这不是尾调用,因此它进入堆栈。反过来,绑定该计算会导致尝试绑定它自己的左侧部分,即 f 1 *> f 2 *> f 3,依此类推,一直到 f 1。所以堆栈炸了。

traverse_(和for_)真的不能做得更好,因为它们都是纯的,所以它们不能运行效果,所以它们所能做的就是建立一个链他们希望其他人稍后会执行它。

答案就在于此:为什么不使用确实知道如何运行效果的特殊版本的 traverse_

看哪:ap,which in turn relies on monadic bind

这是一个有点类似于 Foldable 的类型类,但具有内置的效果。基本上可以折叠一个序列,但是折叠功能是有效的。

这允许在不破坏堆栈的情况下运行一系列效果,但有一个不同的问题:您不能忽略最终结果。如果您有一个包含 100K 个元素的数组开始,您将在最后得到另一个。谢天谢地,这不是一个大问题。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?
Java在半透明框架/面板/组件上重新绘画。
Java“ Class.forName()”和“ Class.forName()。newInstance()”之间有什么区别?
在此环境中不提供编译器。也许是在JRE而不是JDK上运行?
Java用相同的方法在一个类中实现两个接口。哪种接口方法被覆盖?
Java 什么是Runtime.getRuntime()。totalMemory()和freeMemory()?
java.library.path中的java.lang.UnsatisfiedLinkError否*****。dll
JavaFX“位置是必需的。” 即使在同一包装中
Java 导入两个具有相同名称的类。怎么处理?
Java 是否应该在HttpServletResponse.getOutputStream()/。getWriter()上调用.close()?
Java RegEx元字符(。)和普通点?