如何在(功能)F# 中创建递归数据结构值?
type: 的值如何
type Tree =
| Node of int * Tree list
具有以函数方式生成的引用自身的值?
对于树的合适定义,结果值应等于以下 Python 代码中的 x:
x = Tree()
x.tlist = [x]
编辑:显然需要更多解释。我正在尝试学习 F# 和函数式编程,因此我选择实现 覆盖树以前用其他语言编程过。这里相关的是,每个级别的点都是下面级别的点的子集。该结构在概念上达到了无穷级。
在命令式语言中,节点有一个包含其自身的子节点列表。我知道这可以在 F# 中强制完成。不,考虑到覆盖树算法,它不会创建无限循环。
How can a value of type:
type Tree =
| Node of int * Tree list
have a value that references itself generated in a functional way?
The resulting value should be equal to x in the following Python code, for a suitable definition of Tree:
x = Tree()
x.tlist = [x]
Edit: Obviously more explanation is necessary. I am trying to learn F# and functional programming, so I chose to implement the cover tree which I have programmed before in other languages. The relevant thing here is that the points of each level are a subset of those of the level below. The structure conceptually goes to level -infinity.
In imperative languages a node has a list of children which includes itself. I know that this can be done imperatively in F#. And no, it doesn't create an infinite loop given the cover tree algorithm.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
Tomas 的回答提出了两种在 F# 中创建递归数据结构的可能方法。第三种可能性是利用记录字段支持直接递归的事实(当在定义记录的同一程序集中使用时)。例如,以下代码可以正常工作:
使用此列表类型而不是内置列表类型,我们可以使您的代码正常工作:
Tomas's answer suggests two possible ways to create recursive data structures in F#. A third possibility is to take advantage of the fact that record fields support direct recursion (when used in the same assembly that the record is defined in). For instance, the following code works without any problem:
Using this list type instead of the built-in one, we can make your code work:
如果递归引用没有延迟(例如包装在函数或惰性值中),则不能直接执行此操作。我认为动机是没有办法“立即”通过立即引用来创造价值,因此从理论角度来看这会很尴尬。
但是,F# 支持递归值 - 如果递归引用被延迟,您可以使用这些值(F# 编译器随后将生成一些代码来初始化数据结构并填充递归引用)。最简单的方法是将引用包装在惰性值中(函数也可以工作):
另一种选择是使用突变来编写它。然后你还需要使你的数据结构可变。例如,您可以存储
ref
而不是Tree
:正如 James 提到的,如果您不允许这样做,您可以拥有一些不错的属性,例如任何遍历该数据结构的程序都将终止(因为数据结构是有限的并且不能递归)。因此,您需要对递归值更加小心:-)
You cannot do this directly if the recursive reference is not delayed (e.g. wrapped in a function or lazy value). I think the motivation is that there is no way to create the value with immediate references "at once", so this would be awkward from the theoretical point of view.
However, F# supports recursive values - you can use those if the recursive reference is delayed (the F# compiler will then generate some code that initializes the data structure and fills in the recursive references). The easiest way is to wrap the refernece inside a lazy value (function would work too):
Another option is to write this using mutation. Then you also need to make your data structure mutable. You can for example store
ref<Tree>
instead ofTree
:As James mentioned, if you're not allowed to do this, you can have some nice properties such as that any program that walks the data structure will terminate (because the data-structrue is limited and cannot be recursive). So, you'll need to be a bit more careful with recursive values :-)