无法仅在mli文件中定义异常

3

好的,这主要是关于好奇心,但我发现它太奇怪了。

假设我有这段代码

sig.mli

type t = A | B

main.ml

 let f = 
   let open Sig in
   function A | B -> ()

如果我编译,一切都会正常工作。

现在,让我们尝试修改sig.mli

sig.mli

type t = A | B
exception Argh

main.ml 相关。

main.ml

 let f = 
   let open Sig in
   function 
     | A -> ()
     | B -> raise Argh

让我们尝试编译它:

> ocamlc -o main sig.mli main.ml
  File "main.ml", line 1:
  Error: Error while linking main.cmo:
  Reference to undefined global `Sig'

那么,这是因为我添加了异常吗?也许这意味着异常像函数或模块一样,需要适当的实现。

但是,如果我写:

main.ml

 let f = 
   let open Sig in
   function A | B -> ()

尝试编译吗?
> ocamlc -o main sig.mli main.ml
>

它起作用了!如果不使用异常,它就可以编译通过!

没有理由出现这种行为,对吧?(我在不同的编译器上进行了测试,3.12.0、4.00.0、4.02.3和4.03.0,所有编译器都给出了相同的错误)

2个回答

7

与变量不同,异常不是纯类型,需要在.ml文件中实现。请使用ocamlc -dlambda -c x.ml编译以下代码:

let x = Exit

-- the output --
(setglobal X!
  (seq (opaque (global Pervasives!))
    (let (x/1199 = (field 2 (global Pervasives!)))
      (pseudo _none_(1)<ghost>:-1--1 (makeblock 0 x/1199)))))

您可以看到 (let (x/1999 = (field 2 (global Pervasives!))).. 这意味着将存储在模块 Pervasives 的第 2 个位置上的值赋给了变量Exit。异常有它们的值,因此需要 .ml

变体不需要实现。这是因为它们的值可以纯粹地从它们的类型信息(构造函数的标记整数)来构建。我们无法为异常(以及它们的广义版本,开放式类型构造函数)分配标记整数,因为它们是公开定义的。相反,它们在 .ml 中定义值来进行身份识别。


感谢您的回答。我仍然认为编译器的错误信息可以改进,因为它完全不清楚问题出在哪里。;-) - Lhooq
1
我仍然有一个问题,即如果我不使用它,就不会出现编译器错误。 - Lhooq
1
我认为这与C语言相似,你可以在头文件中声明一个函数,只有在使用它时才会得到链接器错误。虽然这确实不直观。 - lambda.xy.x
1
@Lhooq,它与普通值完全相同。在分离编译阶段,声明它们只在 mli 文件中而不给出实现是没有问题的。连接是另一回事。 - camlspotter

2
要实现异常处理,您需要使用 sig.ml 文件。 .mli 文件是接口文件,而 .ml 文件则是实现文件。
对于这个简单的示例,您只需将 sig.mli 重命名为 sig.ml 即可:
$ cat sig.ml
type t = A | B
exception Argh
$ cat main.ml
let f = 
    let open Sig in
    function
    | A -> ()
    | B -> raise Argh
$ ocamlc -o main sig.ml main.ml

我认为这种做法没有问题,但最好不要在.ml和.mli文件之间重复使用类型和异常。当前的设置具有简单和明确的优点。(我不喜欢编译器太聪明并在背后做事情。)

1
亲爱的Joffrey,这正是我所说的。你可以在.mli中放置一个类型而不需要.ml,并且不会有任何问题。实际上,我添加了一个.ml来解决这个问题,但从camlspotter的答案中可以看出这不是一个简单的答案。;-) - Lhooq
正如您所看到的,我知道错误在哪里,但想知道异常和类型之间的行为差异是什么。 - Lhooq
顺便说一下,很高兴你很高兴有更多的OCaml回答者。;-) - Lhooq

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接