Exception Can';t仅在mli文件中定义异常
好吧,这主要是出于好奇,但我觉得太奇怪了 让我们假设我有这个代码 sig.mliException Can';t仅在mli文件中定义异常,exception,module,ocaml,signature,Exception,Module,Ocaml,Signature,好吧,这主要是出于好奇,但我觉得太奇怪了 让我们假设我有这个代码 sig.mli type t = A | B type t = A | B exception Argh main.ml let f = let open Sig in function A | B -> () let f = let open Sig in function | A -> () | B -> raise Argh let f =
type t = A | B
type t = A | B
exception Argh
main.ml
let f =
let open Sig in
function A | B -> ()
let f =
let open Sig in
function
| A -> ()
| B -> raise Argh
let f =
let open Sig in
function A | B -> ()
如果我编译,一切都会工作
现在,让我们尝试修改sig.mli
sig.mli
type t = A | B
type t = A | B
exception Argh
和main.ml
main.ml
let f =
let open Sig in
function A | B -> ()
let f =
let open Sig in
function
| A -> ()
| B -> raise Argh
let f =
let open Sig in
function A | B -> ()
让我们试着编译它:
> 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 -> ()
let f =
let open Sig in
function
| A -> ()
| B -> raise Argh
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,它们都给出了相同的错误)要实现异常,需要
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
文件之间重复类型和异常。当前设置的优点是简单明了。(我不喜欢编译器太聪明,在我背后做事。)与变体不同,exception不是纯类型,需要在.ml
文件中实现。使用ocamlc-dlambda-cx.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)))))
让x=退出
--输出--
(SETX!
(seq(不透明(全球渗透物!))
(设(x/1199=(字段2(全局渗透物!))
(伪u none_u1):-1--1(makeblock 0x/1199(()))
您可以看到(让(x/1999=(字段2(全局渗透!))…
,这意味着分配存储在2
模块渗透
的nd位置中的值。这是退出
的值。异常有其值,因此需要.ml
变量不需要实现。这是因为它们的值可以完全从它们的类型信息构造:构造函数的标记整数。我们不能将标记整数分配给异常(以及它们的通用版本,开放类型构造函数)因为它们是公开定义的。相反,它们在
.ml
中定义了它们的标识值亲爱的Joffrey,这正是我所说的。你可以在.mli
中输入一个类型,而不使用.ml
,你就不会有任何问题。我实际上添加了.ml
来克服这个问题,但从camlspotter的回答来看,你可以看,这不是一个简单的答案。;-)正如您所看到的,我知道错误是什么,但想知道异常和类型之间的行为为何不同。顺便说一下,很高兴您很高兴有更多的OCaml应答者。;-)谢谢你的回答。我仍然认为来自编译器的错误消息可以改进,因为完全不清楚问题出在哪里。;-)我仍然有一个问题,如果我不使用它,就不会有编译器错误。我认为这类似于C,在C中,你可以在头中声明一个函数,并且只会在你使用它时得到链接器错误。当然是不直观的。@Lhooq,它和普通值一样。在分离编译阶段,只在mli
文件中声明它们而不给出它们的实现是没有问题的。链接是另一回事。