递归模块中的 OCaml 类型绑定(bind)

标签 ocaml

我正在尝试在 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 的匹配中,编译失败,并出现 错误:未绑定(bind)类型构造函数 f

我不明白为什么会发生这种情况 - 字段 foo 被定义为具有类型 map_t = int -> Foo.tf 具有签名 int -> Foo.t

我还尝试简单地将记录字段 foo 引用为 foo 而不是 Bar.foo (在 的匹配情况下>B - 这给了我一个 Error: unbound record field foo 错误)。

非常感谢您收到的任何指示或建议。

史蒂夫

最佳答案

  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

关于递归模块中的 OCaml 类型绑定(bind),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37437370/

相关文章:

ocaml - ReScript 中的无限列表/流

ocaml - 在 OCaml 中手动减少列表

用于类型检查类似于 ML 的模式匹配的算法?

ide - OCaml 类型导向的 API 搜索

oop - OCaml 对象中的递归函数

compiler-errors - OCaml 中的递归函数返回未绑定(bind)值错误

ocaml - 是否有理由保留 .cmo 或仅保留 .cma?

testing - 跨不同版本的 OCaml 的可重复性和随机模块

list - 我想在 "then"语句中的 "if.. then.. else"语句之后做两件事

OCaml 在运行时编译和加载