Последняя серия про ocamldep, и потом я перейду к ocamlbuild.
Создадим три файла, a.ml, b.ml и c.ml:
Теперь создадим две "программы" abc.ml и bc.ml, которые их используют:
Для того, чтобы собрать abc.ml, достаточно предварительно скомпилировать a.ml и c.ml.
Для того, чтобы собрать bc.ml, достаточно иметь скомпилированным только b.ml.
Теперь поглядим, что думает по этому поводу ocamldep:
А все потому, что ocamldep не анализирует .cmi файлы и не заглядывает
в .ml файлы, и поэтому он не знает, какие еще модули определены в
a.ml. Для языка с first-class modules это непростительно.
Еще раз напомню, что ocamldep используется всеми без исключения
существующими инструментами для сборки, и все они, волей-неволей,
вынуждены обходить ограничения ocamldep как-то по своему.
Создадим три файла, a.ml, b.ml и c.ml:
a.ml ==== let a = 1 module B = struct let b = 1 ; end b.ml ==== let b = 1 module C = struct let c = 1 ; end c.ml ==== let c = 1
Теперь создадим две "программы" abc.ml и bc.ml, которые их используют:
abc.ml ====== open A open B open C bc.ml ===== open B open C
Для того, чтобы собрать abc.ml, достаточно предварительно скомпилировать a.ml и c.ml.
Для того, чтобы собрать bc.ml, достаточно иметь скомпилированным только b.ml.
Теперь поглядим, что думает по этому поводу ocamldep:
% ocamldep -native abc.ml bc.ml abc.cmx: c.cmx b.cmx a.cmx bc.cmx: c.cmx b.cmx
А все потому, что ocamldep не анализирует .cmi файлы и не заглядывает
в .ml файлы, и поэтому он не знает, какие еще модули определены в
a.ml. Для языка с first-class modules это непростительно.
Еще раз напомню, что ocamldep используется всеми без исключения
существующими инструментами для сборки, и все они, волей-неволей,
вынуждены обходить ограничения ocamldep как-то по своему.
(no subject)
Date: 2011-11-21 12:53 pm (UTC)(no subject)
Date: 2011-11-21 01:03 pm (UTC)1)Из коробки все плохо
2)Мало документации для того, чтобы самому сделать хорошо
А у меня тут сейчас немерянный объем кода, который худо-бедно собирался тем, что есть, периодически все это ломалось, или собирало не то, или собирало не так, и вот наконец произошел количественно-качественный переход, и кол-во проблем стало переваливать через "болевой порог" слишком уж часто.
Мне надо сделать все красиво, я стал копать глубже, чтобы понять, от чего проблемы, там - вот такое ...
Да, по факту мне сейчас не нравится инфраструктура, а точнее - то, что проблемы в ней чинятся не там, где возникают, а заплатками где-то еще. Сам OCaml - OK.
(no subject)
Date: 2011-11-21 01:05 pm (UTC)(no subject)
Date: 2011-11-21 02:44 pm (UTC)Как соберётся abc, если вообще в природе нет модуля А?
F# в таком случае заругается на строку:
open A
(no subject)
Date: 2011-11-21 02:44 pm (UTC)(no subject)
Date: 2011-11-21 02:52 pm (UTC)(no subject)
Date: 2011-11-21 02:54 pm (UTC)(no subject)
Date: 2011-11-21 03:13 pm (UTC)То есть, если в файле a.ml определён module B, то его полное имя A.B - правильно?
А если нет (имя модуля плоское, без неймспейсов), то как будет работать такое:
Это один и тот же x из одного и того же модуля, или разные?
Фа-диез на файлы плюёт, кроме условия, что модуль не может быть разорван на два файла.
open применяется (http://msdn.microsoft.com/en-us/library/dd393787.aspx) только к неймспейсам и модулям. Которые должны быть или в assembly references, или в файлах, которые идут в этом же проекте перед текущим файлом.
C этой точки зрения проще, но с майкрософтовским "шармом": циклические ссылки могут быть только в рамках одного файла.
(no subject)
Date: 2011-11-21 05:03 pm (UTC)Без open-ов можно ссылаться по полному имени: A.B.b и B.b, и это будут разные "b"
Только в ocaml нету неймспейсов, и это просто модули определенные внутри модулей.
(no subject)
Date: 2011-11-21 06:48 pm (UTC)А ещё вопрос - тогда, в Вашем примере, как трактуется команда:
open B
-- это эквивалент "open *.B"? В смысле, который из "B" будет открыт - тот, который A.B, или тот, который в файле b.ml?
И второе. А зачем вообще нужно, чтобы модуль был first-class? Вы его собираетесь в closure вставлять или в переменную? Если заглянуть в то, что делает компилятор фа-диеза, то модули как раз рендерятся в static классы. Вот код a.fs (определение модуля в первой строке обязательно, потому что не соберётся):
А вот, во что оно рендерится:
public static class A { public static int a { get; } public static class B { public static int b { get; } } }Только вот зачем?
(no subject)
Date: 2011-11-21 09:43 pm (UTC)Конструкция "open B" помещает в текущий scope все определения из того B, который "есть под рукой". Т.к. у нас уже есть B, определенный в A - будет взят именно он. А если никакого нет - компилятор пойдет искать по search path.
Зачем модули first-class - это вопрос, скорее, к авторам языка. Наверное, затем, чтобы type classes не делать и отмазываться - вот, мол, есть же модули, нафига вам еще что-то? :)
Моя конкретно претензия в том, что модули first-class в наличии есть, а нормальный dependency analyzer - не завезли.
(no subject)
Date: 2011-11-21 10:51 pm (UTC)"Есть под рукой" - имхо, это очень опасный паттерн. Лично для меня он примерно равен тому, как если бы у нас были A.doSomething и B.doSomething, и компилятор бы молча схавал конструкцию вида doSomething (как в случае отсутствия open, так и в случае, если <open> оба их них). Лучше пусть падает.
> чтобы type classes не делать
Здесь тоже неочевидно.
В случае mutable типов - всё понятно, как минимум, два кита ООП обязательны: инкапсуляция и полиморфизм.
А в случае чистого ФП - хоть я и не являюсь большим идеологом - но мне кажется, что closures являются более "идейным" решением. То есть, передавать не "A", а "A.doSomething". Ведь после вызова никаких артефактов в вызываемом коде ("A") не останется.
Опять же, фа-диез изначально строится на IL, там без классов никуда - но только в реализации.
Но передавать в качестве аргументов модули - это, имхо, глубокий изврат - разве нет? :)
> нормальный dependency analyzer - не завезли.
dependency любого модуля - это список его <open> минус список тех из них, которые реально не используются :)) Потому модули first-class - скорее, бага, чем фича.
Everything above - это глубокое имхо человека, который только изучает ФП.
(no subject)
Date: 2011-11-22 10:42 am (UTC)Вроде в ocaml если два модуля импортируют один и тот-же символ то будет конфликт при его использовании без уточнения имени модуля.
У тебя какая-то странная мешанина из модулей и замыканий. Они как-бы разные вещи. Основное (нетривиальное) назначение модулей -- протаскивание типов в функторы.
Пары-тройку годных примеров использования first-class модулей можно увидеть например тут (http://caml.inria.fr/pub/docs/manual-ocaml/manual021.html#toc81).