如何输入类型的值:
type Tree =
| Node of int * Tree list
有一个引用自身以函数方式生成的值吗?
对于Tree的合适定义,结果值应该等于以下Python代码中的x:
x = Tree()
x.tlist = [x]
修改:显然需要更多解释。我正在尝试学习F#和函数式编程,因此我选择实现之前用其他语言编写的cover tree。这里相关的是每个级别的点是下面级别的点的子集。结构在概念上达到了水平 - 无限。
在命令式语言中,节点有一个包含自身的子列表。我知道这可以在F#中强制执行。不,它不会在封面树算法的情况下创建无限循环。
答案 0 :(得分:9)
Tomas的回答提出了两种在F#中创建递归数据结构的方法。第三种可能性是利用记录字段支持直接递归的事实(当在定义记录的同一程序集中使用时)。例如,以下代码没有任何问题:
type 'a lst = Nil | NonEmpty of 'a nelst
and 'a nelst = { head : 'a; tail : 'a lst }
let rec infList = NonEmpty { head = 1; tail = infList }
使用此列表类型而不是内置类型,我们可以使您的代码工作:
type Tree = Node of int * Tree lst
let rec x = Node(1, NonEmpty { head = x; tail = Nil })
答案 1 :(得分:7)
如果递归引用没有延迟(例如包裹在函数或惰性值中),则不能直接执行此操作。我认为动机是没有办法用“立刻”立即引用来创造价值,所以从理论的角度来看这将是尴尬的。
但是,F#支持递归值 - 如果递归引用被延迟,您可以使用它们(F#编译器将生成一些初始化数据结构并填充递归引用的代码)。最简单的方法是将refernece包装在一个惰性值中(函数也可以工作):
type Tree =
| Node of int * Lazy<Tree list>
// Note you need 'let rec' here!
let rec t = Node(0, lazy [t; t;])
另一个选择是使用变异来写这个。然后,您还需要使您的数据结构可变。例如,您可以存储ref<Tree>
而不是Tree
:
type Tree =
| Node of int * ref<Tree> list
// empty node that is used only for initializataion
let empty = Node(0, [])
// create two references that will be mutated after creation
let a, b = ref empty, ref empty
// create a new node
let t = Node(0, [a; b])
// replace empty node with recursive reference
a := t; b := t
正如James所说,如果你不允许这样做,你可以拥有一些不错的属性,例如任何遍历数据结构的程序都将终止(因为数据结构是有限的,不能递归)。所以,你需要对递归值更加小心: - )