Ocaml 自参考
我已经创建了类型 t = Test of int * t ref
如何创建类型 t 的任何对象?
I've created type t = Test of int * t ref
How to create any object of type t?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
正如delnan所说,您可以使用循环值:
虽然递归通常用于定义函数,但对于某些值是可能的。这通常是不可能的,文档中描述了一些限制< /a>.
这个想法是,这个值是堆分配的,所以很容易递归地使用它:首先为“Test”构造函数分配空间,然后你可以使用“x”分配的构造函数的地址来定义它的字段,甚至如果它指向一个尚未完全定义的值。函数、惰性值、对、记录等都遵循这种模式。当然,规范并不是那么低级(OCaml手册中没有定义“堆分配”),有一个稍微更严格的语法规范。
一旦你通过值递归引导了一个值,你就可以构建更复杂的值:
你也可以直接这样做
。尽管不推荐,也可以使用由
Obj
生成的“虚拟值” 。这就是标准库的Queue
模块的实现方式。此定义的一个问题是值是循环的。如果您打算迭代这些值的“尾部”,这可能会出现问题。如果您打算使用 int 字段来跟踪结构的“尾部长度”(0 表示引用是一个不应跟随的虚拟指针),这正是
Queue
模块已实施。还有其他可能的选择。例如,您可以使用一个模型,其中通过使用选项类型明确尾部指针的可空性:
在这种情况下,您不需要递归来引导您的类型,
None
就足够了。当然,由于选项类型具有间接性,因此这会带来适度的性能成本。PS:请注意,对于像这样的单构造函数类型,使用记录类型可能会更好:
As delnan said, you can use cyclic values :
While recursion is generally used to define functions, it is possible for certain values. This is not possible in general, there are restrictions described in the documentation.
The idea is that this value is heap-allocated, so it is easy to use it recursively : allocate the space for a "Test" constructor first, then you can define its field using for "x" the adress of the allocated constructor, even if it points to a not-yet-fully-defined value. Functions, lazy values, pairs, records, etc., all follow this pattern. Of course, the specification is not so low-level ("heap-allocated" is not defined in the OCaml manual), there is a slightly more restrictive syntaxic specification.
Once you have bootstrapped a value by value recursion, you can build more elaborate values :
You can also do that directly
It is also possible, though really not recommended, to use a "dummy value" produced by
Obj
. This is how theQueue
module of the standard library is implemented.An issue with this definition is that the values are cyclic. It can be problematic if you plan to iterate on the "tail" of such values. If you plan to use the int field to keep track of the "tail length" of the structure (0 means the reference is a dummy pointer that shouldn't be followed), this is exactly how the
Queue
module is implemented.There are other options possible. You may for example use a model where the nullability of the tail pointer is made explicit by using an option type :
In that case, you don't need recursion to bootstrap your type,
None
is enough. Of course, as option types have an indirection, this comes at a moderate performance cost.PS : note that for one-constructor types such as this one, you may be better with a record type: