【问题标题】:OCaml type binding in recursive modules递归模块中的 OCaml 类型绑定
【发布时间】:2016-05-25 12:36:10
【问题描述】:

我正在尝试在 ocaml 中构建一系列递归模块。这是一个最简单的例子:

  module rec Foo : sig
    type t =
      | A of int
      | B of Foo.t
  end = struct
    type t =
      | A of int
      | B of Foo.t
  end       

  module rec Bar : sig
    open Foo
    type map_t = int -> Foo.t
    type t = { foo : map_t }
    val bar_of_foo : Foo.t -> t
  end = struct
    open Foo

    let rec bar_of_foo f = match f with
      | A a -> let ff (_:int) = a in 
               { Bar.foo = ff }
      | B b -> { foo = bar_of_foo b.foo } 
  end

在函数 bar_of_foo 中编译失败,在 A 的匹配中,与 Error: unbound type constructor f

我不明白为什么会这样 - 字段 foo 被定义为具有类型 map_t = int -> Foo.t,而 f 具有签名 int -> Foo.t

我还尝试将记录字段 foo 简单地称为 foo 而不是 Bar.foo(在 B 的匹配案例中 - 这给了我一个 Errror: unbound record field foo 错误)。

感激地收到任何指示或建议。

史蒂夫

【问题讨论】:

  • (1) 最里面的f(最外面的fbar_of_foo 的参数)具有签名int -> int,因为它使用a : int 作为其返回值。我认为删除名称冲突是个好主意。 (2) 我看不到FooBar 之间的递归依赖关系。我只是看到Bar 使用Foo,但不是相反。
  • 谢谢安东。在帖子中删除了名称冲突。
  • 好的,所以我不明白bar_of_foo 中的打字是如何解决的。第一行:` | A a -> let ff (_:int) = a in { Bar.foo = ff }` 从匹配 A ( = Foo.A) 类型开始。而且,Foo.A 的类型是int。所以我明白为什么ff 的签名是int -> int。但是A是Foo.t的变种之一,那为什么bar_of_foo可以没有签名Foo.t -> int呢?

标签: ocaml


【解决方案1】:
  1. 由于bar_of_foo 是一个函数,它的类型为x -> y
  2. 类型推断算法发现您对Foo.t 的构造函数上的参数f 进行模式匹配。这个事实修复了x = Foo.t
  3. 当您返回 {foo = ...} 时,系统会收到 y = Bar.t(或者在我们的上下文中只是 t)。
  4. 那么,bar_of_foo : Foo.t -> Bar.t

下面的代码可以编译,和OP中的代码类似:

module Foo : sig
  type t =
  | A of int
  | B of t
  end = struct
  type t =
      | A of int
      | B of t
  end

module Bar : sig
  type map_t = int -> Foo.t
  type t = { foo : map_t }
  val bar_of_foo : Foo.t -> t
  end = struct
    open Foo

    type map_t = int -> Foo.t
    type t = { foo : map_t }

    let rec bar_of_foo f = match f with
      | A a -> { foo = fun (_:int) -> A a }
      | B b -> bar_of_foo b 
  end

测试:

open Foo
open Bar

let () =
  let bar = bar_of_foo (B (B (B (A 42)))) in
  match (bar.foo 0) with
    | A n -> print_int n; print_newline ()
    | B _ -> print_string "Impossible!\n"

还有输出:

$ ocaml example.ml
$ 42

请注意,模块 FooBar 不是相互递归的。否则我们将不得不写

module rec Foo : sig
  ...
  end = struct
  ...
  end
and Bar : sig
  ...
  end = struct
    ... 
  end

【讨论】:

  • 哈!我终于自己解决了,当你也打败了我时,我正在回答我自己的问题。非常感谢你的帮助 - 你和 camlpost 帮助我到达那里:-)
  • 对类型推理的一个非常清晰的阐述:-)
【解决方案2】:

这个答案现在是多余的,因为这里指出的事情已经反映到问题上。

记录表达式中的语法错误。使用= 而不是:,即{ Bar.foo = f }{ foo = bar_of_foo b }

之后,您的代码仍有一些打字问题。例如,bar_of_foo b 的类型为t,因此它不能用作tfoo 成员。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-07-01
    • 1970-01-01
    • 2015-06-10
    • 1970-01-01
    • 1970-01-01
    • 2014-03-01
    • 2016-02-02
    相关资源
    最近更新 更多