使用依赖的变体

时间:2017-08-25 06:01:11

标签: ocaml

我有这段代码:

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.

我是以错误的方式使用变体,还是错误地使用了编译器?

1 个答案:

答案 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的值。