我有这段代码:
cnf.mli
type literal
type clause
type cnf
type l_diff
val l_compare: literal -> literal -> l_diff
cnf.ml(部分)
type l_diff = Same | Negation | Different
checker.ml(部分)
open Cnf
type solution = (literal * bool) list
let rec solve_literal sol l =
match sol with
| [] -> false
| (hl, b)::rs when (l_compare l hl) = Same -> b
| (hl, b)::rs when (l_compare l hl) = Negation -> not b
| _::rs -> solve_literal rs l
这适用于utop使用:
#mod_use "cnf.ml";;
#use "checker.ml";;
但如果我尝试编译checker
,我会收到以下错误:
编译命令:
ocamlbuild cnf.cma
ocamlbuild checker.cma
错误:
+ /home/user/.opam/4.05.0/bin/ocamlc.opt -c -o checker.cmo checker.ml
File "checker.ml", line 7, characters 42-46:
Error: Unbound constructor Same
Hint: Did you mean Some?
Command exited with code 2.
Compilation unsuccessful after building 6 targets (2 cached) in 00:00:00.
我是以错误的方式使用变体,还是错误地使用了编译器?
答案 0 :(得分:5)
两者都没有,你以错误的方式在签名中使用抽象类型。当您在cnf.mli
type l_diff
这将类型l_diff
声明为抽象类型,换句话说是一个隐藏内容的黑盒子。
相反,当使用#mod_use "cnf.ml"
时,顶层会自行推断签名并使所有类型声明透明:
type literal = …
type clause = …
type cnf = …
type l_diff = Same | Negation | Different
val l_compare: literal -> literal -> l_diff
(如果您希望查看完整的推断签名ocamlbuild cnf.inferred.mli
应该有效。)
使用此签名,l_diff
的构造函数是可见的,可以直接构造类型l_diff
的模式匹配值。
更一般地说,您的签名cnf.mli
限制性太强:
使用此签名,创建l_diff
类型值的唯一方法是调用l_compare
。然而,然后不可能观察到该类型的内容。同样,使用您提供的接口cnf.mli
,无法创建类型literal
的值。