Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/357.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
单个OCaml模块导致对接口的假设不一致_Ocaml_Ocamlbuild - Fatal编程技术网

单个OCaml模块导致对接口的假设不一致

单个OCaml模块导致对接口的假设不一致,ocaml,ocamlbuild,Ocaml,Ocamlbuild,以下是我基于ocamlbuild的项目结构: _tags.ml: true: package(batteries) Main.mlpack Stream Main/Stream.ml module MyStream = BatStream 我正在尝试使用编译Main模块 ocamlbuild -use-ocamlfind Main.cmo 在我看来,错误消息似乎不合逻辑: + ocamlfind ocamlc -pack Main/Stream.cmo -o Main.cmo File

以下是我基于ocamlbuild的项目结构:

_tags.ml:

true: package(batteries)
Main.mlpack

Stream
Main/Stream.ml

module MyStream = BatStream
我正在尝试使用编译
Main
模块

ocamlbuild -use-ocamlfind Main.cmo
在我看来,错误消息似乎不合逻辑:

+ ocamlfind ocamlc -pack Main/Stream.cmo -o Main.cmo
File "_none_", line 1:
Error: The files Main/Stream.cmi and Main/Stream.cmi
       make inconsistent assumptions over interface Stream
Command exited with code 2.
Compilation unsuccessful after building 3 targets (0 cached) in 00:00:00
这是使用OPAM中的OCaml 4.02.1

这仅在与电池链接时发生,因此我只能判断
batters.Stream
Main.Stream
之间存在冲突。事实上,如果我添加更多具有依赖关系的模块,我可以得到如下消息

Error: The files /home/ken/.opam/4.02.1/lib/batteries/batteries.cmi
       and Main/Stream.cmi make inconsistent assumptions
       over interface Stream
但是,我不希望子模块发生冲突


为什么会这样?在我看来,模块不可能在接口上与自身发生冲突。

BatStream
扩展了stdlib
模块。本地
模块和stdlib
模块之间可能存在冲突。

BatStream
扩展stdlib
模块。本地
模块和stdlib
模块之间可能存在冲突。

OCaml有一个用于编译单元名称的平面命名空间。当编译单元使用某个模块时,它会记录模块接口的名称和摘要(基本上是接口的CRC)。一致性检查确保具有相同名称的两个接口具有相同的摘要(基本上表示相同的实现)。尽管错误消息确实具有误导性,但它仍然是正确的(尽管措辞可能更好)。让我们使用
ocamlobjinfo
工具:

$ ocamlobjinfo _build/Main/Stream.cmi
File _build/Main/Stream.cmi
Unit name: Stream
Interfaces imported:
        83d31bf1e61f22b62a8b2728a55f2593        Stream
        d0b21ad0c1f4e93fa8c05b9ded519b52        Stream
        999b28e3b7638771c87eebf5a8325e42        Pervasives
        60c2e7663dd57d13b5920931742e1c10        Format
        9642e3ed163e46770985ca668738ed5f        CamlinternalFormatBasics
        6dc691300ced97c0e319cbcc0a715044        Bytes
        3bd1af04573ce2da7fc3dc04403e852e        Buffer
        383683999ce4d4a54f1689bb92969ecb        BatStream
        fbefc52bb310bf525973099141e16ffe        BatOrd
        92bc9ee9d7e3da3421ed7fc5c0ade74d        BatInterfaces
        7d12ec9e52c91f3af313796ff85158c4        BatInnerIO
        6f57ab9f63c2f00619c3ffc9bde0bc80        BatIO
        bd48c0243cabeabfa9ba81aa02319882        BatEnum
        1972feae99a1525e1b830ca37c4efa20        BatConcurrent
我们导入了两个名称相同但实现不同的接口(CRC总和不同)。第一个接口实际上是
模块的接口,第二个接口是标准流模块的接口:

$ ocamlobjinfo /home/ivg/.opam/devel/lib/ocaml/stream.cmi
File /home/ivg/.opam/devel/lib/ocaml/stream.cmi
Unit name: Stream
Interfaces imported:
        d0b21ad0c1f4e93fa8c05b9ded519b52        Stream
        999b28e3b7638771c87eebf5a8325e42        Pervasives
        9642e3ed163e46770985ca668738ed5f        CamlinternalFormatBasics
正如您可能注意到的,每个模块总是导入自己的接口。因此,冲突出现在您的
模块和OCaml的
模块之间。标准的
Stream
模块通过
BatStream
模块进入编译单元

总而言之。接口名称空间是平面的,所以您需要使用前缀来防止冲突,参见
BatStream
。是的,很难看


模块打包可以帮助您防止打包到包中的模块与使用包的模块之间的名称冲突。例如,如果您在包
P
中打包了一个模块
M
,那么您可以将它与另一个模块
M
链接,并且
M
P.M
之间不会有冲突(如果您做的一切都正确)。但是,在构建包时,构成包的模块不应与它们使用的模块冲突,而且不幸的是,OCaml标准库不是包,因此您应该选择与标准库或用于实现包的任何其他库不冲突的名称

OCaml有一个用于编译单元名称的平面名称空间。当编译单元使用某个模块时,它会记录模块接口的名称和摘要(基本上是接口的CRC)。一致性检查确保具有相同名称的两个接口具有相同的摘要(基本上表示相同的实现)。尽管错误消息确实具有误导性,但它仍然是正确的(尽管措辞可能更好)。让我们使用
ocamlobjinfo
工具:

$ ocamlobjinfo _build/Main/Stream.cmi
File _build/Main/Stream.cmi
Unit name: Stream
Interfaces imported:
        83d31bf1e61f22b62a8b2728a55f2593        Stream
        d0b21ad0c1f4e93fa8c05b9ded519b52        Stream
        999b28e3b7638771c87eebf5a8325e42        Pervasives
        60c2e7663dd57d13b5920931742e1c10        Format
        9642e3ed163e46770985ca668738ed5f        CamlinternalFormatBasics
        6dc691300ced97c0e319cbcc0a715044        Bytes
        3bd1af04573ce2da7fc3dc04403e852e        Buffer
        383683999ce4d4a54f1689bb92969ecb        BatStream
        fbefc52bb310bf525973099141e16ffe        BatOrd
        92bc9ee9d7e3da3421ed7fc5c0ade74d        BatInterfaces
        7d12ec9e52c91f3af313796ff85158c4        BatInnerIO
        6f57ab9f63c2f00619c3ffc9bde0bc80        BatIO
        bd48c0243cabeabfa9ba81aa02319882        BatEnum
        1972feae99a1525e1b830ca37c4efa20        BatConcurrent
我们导入了两个名称相同但实现不同的接口(CRC总和不同)。第一个接口实际上是
模块的接口,第二个接口是标准流模块的接口:

$ ocamlobjinfo /home/ivg/.opam/devel/lib/ocaml/stream.cmi
File /home/ivg/.opam/devel/lib/ocaml/stream.cmi
Unit name: Stream
Interfaces imported:
        d0b21ad0c1f4e93fa8c05b9ded519b52        Stream
        999b28e3b7638771c87eebf5a8325e42        Pervasives
        9642e3ed163e46770985ca668738ed5f        CamlinternalFormatBasics
正如您可能注意到的,每个模块总是导入自己的接口。因此,冲突出现在您的
模块和OCaml的
模块之间。标准的
Stream
模块通过
BatStream
模块进入编译单元

总而言之。接口名称空间是平面的,所以您需要使用前缀来防止冲突,参见
BatStream
。是的,很难看


模块打包可以帮助您防止打包到包中的模块与使用包的模块之间的名称冲突。例如,如果您在包
P
中打包了一个模块
M
,那么您可以将它与另一个模块
M
链接,并且
M
P.M
之间不会有冲突(如果您做的一切都正确)。但是,在构建包时,构成包的模块不应与它们使用的模块冲突,而且不幸的是,OCaml标准库不是包,因此您应该选择与标准库或用于实现包的任何其他库不冲突的名称

你试过清理(即,
rm-rf-build
)吗?@Drup确实是这样。包含这三个文件的新项目将生成给定的错误。您是否尝试清理(即,
rm-rf\u build
)?@Drup确实如此。包含这三个文件的新项目将生成给定的错误。但是我的子模块
Main.Stream
肯定不应该与stlib的
Stream
module.OCaml冲突,因为它不使用目录层次结构。您的模块只是
Stream
,而不是
Main.Stream
。我也这么认为。但是我的子模块
Main.Stream
肯定不应该与stlib的
Stream
module.OCaml冲突,因为它不使用目录层次结构。你的模块只是
Stream
,而不是
Main.Stream
。是的,这个解释是100%准确的,但情况很糟糕。是的,这个解释是100%准确的,但情况很糟糕。