F# XLinq 遍历 - 柯里化(Currying)版本的函数抛出 StackOverflowException

标签 f# linq-to-xml currying

我有两个类似的函数 nestednestedCurried,它们使用 XLinq 遍历 XML 树。它们没有做任何有用的事情 - 它只是从更复杂的代码中“缩小”的摘录。

我期望这两个函数以相同的方式运行,对我来说它们看起来是相同的,唯一的区别是 nestedCurried 没有显式声明 e: XElement 参数 - 通过使用 elements 函数和函数组合 >>

同时,nestedCurried 函数在任何 XElement 上调用时抛出 StackOverflowException

在 FSI 中评估:

#r "System.Xml.Linq"
open System.Xml.Linq

let inline elements (e: XElement) = e.Elements() |> Seq.toList

let rec nested () e = elements e |> List.collect (nested ())
let rec nestedCurried () = elements >> List.collect (nestedCurried ())

let x = XDocument.Parse """<a></a>"""

let ok : XElement list = nested () (x.Root)
// Stack Overflow below
let boom : XElement list = nestedCurried () (x.Root)

为什么会发生 StackOverflowException,这两个函数之间的技术区别是什么,以及如何在不指定 XElement 的情况下声明 nested 函数明确论证?

最佳答案

看:每次调用 nestedCurried 时,都会立即无条件地再次调用 nestedCurried

为了让事情更清楚一点,考虑表达式 List.collect f 等同于 let x = f; List.collect x.这意味着您对 nestedCurried 的定义等同于:

let nestedCurried () =
  let x = nestedCurried()
  elements >> List.collect x

现在是否更清楚为什么这会导致无限递归?

关于F# XLinq 遍历 - 柯里化(Currying)版本的函数抛出 StackOverflowException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33887455/

相关文章:

f# - F# 中的空合并运算符?

c# - XAML - 为什么数据绑定(bind) TwoWay 不适用于 .net 4.0 中组合框的文本属性?

haskell - 如何在 Haskell 中应用偏函数

Haskell:了解部分应用程序吗?

haskell - 在haskell中无需递归即可进入范围

c# - 我可以为我不直接控制的两个类添加隐式转换吗?

recursion - 抽象循环

haskell - 如何解决 F# 的类型系统

c# - 使用 linq to xml 获取特定值

c# - 如果子节点元素相等,如何添加父节点?