我正在尝试在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
的匹配情况中 - 这给了我一个{{1}错误)。
感激不尽的任何指示或建议。
史蒂夫
答案 0 :(得分:2)
bar_of_foo
是一个函数,因此它的类型为x -> y
。f
的构造函数上对参数Foo.t
进行模式匹配。这个事实修复了x = Foo.t
。 {foo = ...}
时,系统会在我们的上下文中获得y = Bar.t
(或仅t
。)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
请注意,模块Foo
和Bar
不是相互递归的。否则我们必须写
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}}成员。