【问题标题】:Mutually recursive types in OCamlOCaml 中的相互递归类型
【发布时间】:2015-06-10 21:16:00
【问题描述】:

在 Haskell 中,您可以执行以下操作:

Prelude> data Foo = Foo Bar; data Bar = Bar Foo

如何在 OCaml 中做同样的事情?我试过了:

                    ___
# type foo = Foo of bar;; type bar = Bar of foo;;
Error: Unbound type constructor bar

是否可以在 OCaml 中定义相互递归的数据类型?如果不是那为什么?

比较数据定义以让表达式:相互递归的数据类型对应于使用let rec(或者更合适的是type rec,因为需要更好的短语)。能够定义相互递归的数据类型有什么好处?我的 foobar 示例是微不足道的。您能想到相互递归数据类型的任何重要用途吗?

【问题讨论】:

    标签: haskell recursion ocaml algebraic-data-types mutual-recursion


    【解决方案1】:

    使用and

    type foo = Foo of bar
     and bar = Bar of foo
    

    【讨论】:

    • 显式相互递归。比起 Haskell 语法,我更喜欢它。显式总比隐式好。
    • 它实际上略显烦人。最明确的是type rec foo = Foo of bar and bar = Bar of foo。例如,当存在环境类型 t 并且您想在子模块中创建一个新类型 t 时会遇到(小)问题,该子模块为环境 t 提供别名,但 type t module X = struct type t = t end 是一个错误因为它假设你的意思是构造无限类型type x = x
    • discussion 在这个主题上有一个有趣的几年,这导致了一个新的 nonrec 关键字。在 4.03 中,我们将拥有 type nonrec t 甚至(我不确定它是否会出现在最终补丁中)type rec t
    • 所以type rec 仍然是默认值吗?您可以将声明添加为更加明确吗?
    【解决方案2】:

    ivg 回答了您的问题,但这是一个重要的相互递归类型。

    module Stream = struct
    
      type 'a t    = unit -> 'a node
       and 'a node = Nil
                   | Cons of 'a * 'a t 
    
    end
    

    这是真正的脊椎懒惰流。也就是说,您可以在没有相互递归类型的情况下构造它

    type 'a t = Stream of (unit -> ('a * 'a t) option)
    

    我的想法是,如果你愿意,你总是可以将一系列相互递归的类型简化为一个类型(尽管可能不是在 OCaml 中——我正在考虑的编码将不平凡地使用依赖类型索引) ,但肯定可以直接更清楚。

    【讨论】:

    • 实际上,您的第二个类型定义不起作用,它会说类型定义是循环的。正确的方法是type 'a t = Stream of (unit -> ('a * 'a t) option)
    • 哦,哎呀!是的,没有在解释器中检查它。现已修复,谢谢。
    猜你喜欢
    • 2013-06-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-03
    • 1970-01-01
    相关资源
    最近更新 更多