OCaml中如何将函子生成的模块的类型作为函数入参?
报错根因
你在定义FooExtend函子的返回签名时使用了破坏性代换语法Foo with type t := Arg.t,该语法会直接将Foo模块类型中声明的t类型完全移除,所有用到t的位置都会被替换为入参Arg.t。因此你通过函子生成的FooInt、FooString模块的公开签名里,根本没有导出t这个类型构造器,直接写FooInt.t自然会报「未绑定的类型构造器」错误。
你写的foo'能正常编译的原因也很简单:FooInt.id的类型已经被代换为int -> int,只要传入int类型参数即可正常调用,不需要引用FooInt.t。
解决方法
方法1:改用类型共享约束保留t类型声明
如果你需要通过生成模块的.t来引用对应类型,将函子返回签名的破坏性代换:=改为普通的类型共享约束=即可,同时要在函子实现中补充t的声明:
module FooExtend(Arg : Foo_S) : (Foo with type t = Arg.t) = struct type t = Arg.t let id a = a end
修改后FooInt.t会作为int的别名存在,你写的foo函数就能正常编译。
方法2:直接使用对应原始类型
如果不需要保留生成模块的t别名,直接使用对应入参模块的类型即可,比如FooInt的入参是Int模块,对应类型就是int,直接用int作为参数类型即可,不需要额外修改函子定义。
内容的提问来源于stack exchange,提问作者geckos
相关产品推荐
相关产品推荐

