2017-02-05 10 views
1

Вот мой ocamlbuild структура на основе проекта:одного модуля OCaml вызывает противоречивые предположения относительно интерфейса

_tags.ml:

true: package(batteries) 

Main.mlpack

Stream 

Главная/Stream.ml

module MyStream = BatStream 

I a м пытается скомпилировать модуль 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 

Это использование OCaml 4.02.1 из OPAM.

Это происходит только при соединении с батареями, поэтому я могу только понять, что существует конфликт между Batteries.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 

Однако, я бы не ожидал Подмодули конфликтовать.

Почему это происходит? Мне кажется невозможным, что модуль может конфликтовать с ним над интерфейсом.

+0

Вы пытались очистить (т. Е. 'Rm -rf _build')? – Drup

+0

@Drup Действительно, я сделал. Новый проект, содержащий эти три файла, будет генерировать данную ошибку. –

ответ

3

В 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 суммы различны). Первый интерфейс на самом деле интерфейс вашего Stream модуля, вторая представляет собой интерфейс модуля потока эталона:

$ 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 

Как вы можете заметить, каждый модуль всегда импортирует свой собственный интерфейс. Таким образом, конфликт между вашим модулем Stream и модулем OCaml Stream. Модуль Stream стандарта попал в ваш блок компиляции через модуль BatStream.

Подводя итог. Интерфейсное пространство имен является плоским, поэтому для предотвращения конфликтов необходимо использовать префикс, см., BatStream. Да, это уродливо.

Упаковка модуля может помочь вам предотвратить конфликты имен между модулями, упакованными в пакет, и модули, которые используют пакет.Например, если у вас есть модуль M, упакованный в пакет P, вы можете связать его с другим модулем M и не будет конфликтов между M и P.M (если вы все сделали правильно). Однако при создании пакета модули, составляющие его, не должны иметь конфликтов с используемыми ими модулями и, к сожалению, стандартная библиотека OCaml не является пакетом, поэтому вам следует выбирать имена, которые не сталкиваются со стандартной библиотекой или любую другую библиотеку, которую вы используете для реализации вашего пакета.

+0

Отличное объяснение. Спасибо! –

1

BatStream расширяет модуль stdlib Stream. Вероятно, конфликт между вашим локальным модулем Stream и модулем stdlib Stream.

+0

Я так и предполагал. Но, безусловно, мой * подмодуль * 'Main.Stream' не должен конфликтовать с модулем stlib' Stream'. –

+0

OCaml не использует иерархию каталогов. Ваш модуль - это только 'Stream', а не' Main.Stream'. – Drup