递归模块中的OCaml类型绑定

时间:2016-05-25 12:36:10

标签: 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与Error: unbound type constructor f的匹配中编译失败。

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

我还尝试将记录字段foo称为foo而不是Bar.foo(在B的匹配情况中 - 这给了我一个{{1}错误)。

感激不尽的任何指示或建议。

史蒂夫

2 个答案:

答案 0 :(得分:2)

  1. 由于bar_of_foo是一个函数,因此它的类型为x -> y
  2. 类型推断算法看到您在f的构造函数上对参数Foo.t进行模式匹配。这个事实修复了x = Foo.t
  3. 当您返回{foo = ...}时,系统会在我们的上下文中获得y = Bar.t(或仅t。)
  4. 所以,bar_of_foo : Foo.t -> Bar.t
  5. 以下代码编译,它类似于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
    

答案 1 :(得分:0)

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

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

之后,您的代码仍然存在一些打字问题。例如,bar_of_foo b的类型为t,因此无法用作foo的{​​{1}}成员。