OCaml перекрестные ссылки - PullRequest
6 голосов
/ 01 июля 2010

как работает ссылочная ссылка в OCaml?

Пример, предположим, у меня есть 3 модуля, объявленные как

  • A.ml
  • B.ml
  • C.ml

из которых

  • A нужно B и C
  • B потребности A

Как мне продолжить сборку?

Поскольку порядок имеет значение, используя ocamlc или ocamlopt, как я могу исправить перекрестную ссылку между B и A?

Я пытаюсь сначала скомпилировать их все в .cmo с помощью ocamlc -c, а затем связать их все вместе, но безуспешно, поскольку замена аргументов просто переместит проблему из модуля в другой.

Конкретная ошибка:

Ошибка: ошибка при подключении A.cmo: Ссылка на неопределенное глобальное `B '

(или наоборот, если я поменяю порядок аргументов)

Я думаю, что это простой вопрос, но я не могу его решить .. заранее спасибо

Ответы [ 2 ]

7 голосов
/ 01 июля 2010

Вы должны объединить модули в один файл и сделать их рекурсивными .Я не верю, что есть способ сделать это из процесса компиляции двух отдельных файлов.

module rec A : 
    sig
        val f : int -> int
        val g : int -> int
    end = 
    struct
        let f x = (B.g x) + 1
        let g x = x + 1
    end
and B :
    sig
        val f : int -> int
        val g : int -> int
    end = 
    struct
        let f x = (A.g x) + 1
        let g x = x + 1
    end

РЕДАКТИРОВАТЬ: Я полагаю, из вашего комментария у вас есть определение типа синтаксического анализатора и функции, которые обрабатывают / работают с типом в одном файле.Я согласен с вами, это имеет смысл.Но, как вы уже знаете, если этот файл должен не только работать с типом, но и вызывать анализатор для получения данных, как синтаксический анализатор собирается его создать?Мое решение состояло в том, чтобы разделить тип на его собственный модуль и открыть тот модуль в модуле, который выполняет операции.

Поэтому вы разбиваете A на (A и A'), гдеA' содержит тип, созданный B и используемый в A.Ваши зависимости становятся

  • A потребности A' и B и C
  • B потребности A'

Например, у меня есть парсер для файлов конфигурации, который я использую для запуска любого приложения, которое я пишу.

ConfType   --contains the type t  
Conf       --calls parser, and contains helper functions for type ConfType.t  
ConfParser --for ocamlyacc
ConfLexer  --for ocamllex

Альтернативой всему этому является использование полиморфных вариантов.Таким образом вы удаляете зависимости, так как они определены ad-hoc.Конечно, тип, созданный синтаксическим анализатором, потенциально может отличаться от типа в Conf, и компилятор не сможет помочь вам с ошибкой.

3 голосов
/ 09 июля 2010

Язык Ocaml поддерживает рекурсию между модулями, но компилятор не поддерживает рекурсию между модулями компиляции. Таким образом, вы не можете иметь A.ml нуждающимся B.ml и B.ml нуждающимся A.ml. Рефакторинг для удаления рекурсии лучше, если вы можете сделать это легко, но давайте предположим, что вы не можете.

Одним из решений, как объясняет nlucaroni, является объединение обоих модулей в один файл и использование module rec. Другое решение иногда состоит в том, чтобы превратить один модуль в функтор, например, превратить A в функтор F, который принимает аргумент с подписью B, и скомпилировать сначала файл, определяющий F, затем B затем файл, который просто определяет module A = F(B).

Ocamlyacc делает вещи более сложными, но вы можете обмануть это! Вы можете написать module A = functor (...) -> struct в заголовке .mly и соответствующий end в нижнем колонтитуле. Однако вам придется переписать сгенерированные .mli, чтобы добавить module A : functor (...) -> sig и end как часть процесса сборки. (Я знаю, что делал это раньше, чтобы решить ту же проблему, что и у вас, хотя я не помню, где, поэтому я не могу привести пример из реальной жизни.)

Еще одна возможность, заслуживающая изучения, - это переключение с Ocamlyacc на Menhir , который является заменой Ocamlyacc (практически не требует переноса, так как синтаксис такой же), с некоторыми полезными функциями, которые могут вам помочь, такими как поддержка параметризованных модулей синтаксического анализа (т. е. функторов).

...