Помните, как в крайнем посте я обмолвился, что в OCaml есть генераторы списков , но для их получения нужно произвести дополнительные действия, и в результате использовал указатель на голову списка с циклами for? Настало время выяснить, что это за дополнительные действия такие.

Пример использования генераторов списков в OCaml:

open Batteries_uni

let string_of_list to_string lst =
«[» ^ String . concat «; » ( List . map to_string lst ) ^ «]»

let main ( ) =
let lst = [ ? List : x | x <- 1 10 ; x mod 2 == 1 ? ] in
print_endline ( string_of_list string_of_int lst )

let _ = main ( )

В действительности, конструкцию [ ? ... ? ] неправильно называть генератором списков, поскольку это генератор чего угодно. Например, так можно сгенерировать множество букв латинского алфавита:

[ ? Set : x | x <- a ~ z ? ]

Чтобы получить такое расширение синтаксиса, нам предстоит воспользоваться OCaml Batteries Included (или просто «батарейками»). Это поддерживаемый и развиваемый сообществом OCaml-программистов обширный набор хорошо документированных и согласованных между собой библиотек, а также расширений синтаксиса OCaml. Насколько я могу судить, в наши дни батарейки де-факто являются стандартной платформой для разработки программ на OCaml.

В Debian есть готовый пакет ocaml-batteries-included, который мы установили в прошлый раз. Также нам понадобится система сборки OMake :

sudo aptitude install omake omake-doc

Во FreeBSD, как обычно, все намного интереснее:

pkg_add -r ocaml-findlib ocaml-camomile omake

За неимением готового пакета, под FreeBSD батарейки придется собрать руками:

git clone git: // github.com / ocaml-batteries-team / batteries-included.git
cd batteries-included
git checkout v1.5.0
gmake

Совсем недавно (25.01.13) вышли батарейки версии 2.0 . Однако они зависят от bisect , который под FreeBSD также нужно собирать руками, предварительно забрав исходники из Darcs-репозитория. Думаю, на первое время вполне хватит проверенных временем батареек версии 1.5. Для их установки под рутом говорим:

gmake install
gmake install-doc

Как в Debian, так и во FreeBSD, для использования батареек нам понадобится файл ~/.ocamlinit:

wget https: // raw.github.com / ocaml-batteries-team / batteries-included / master / ocamlinit -O ~ / .ocamlinit

Если теперь запустить интерпретатор OCaml, мы должны увидеть примерно следующее:

Objective Caml version 3.12.1

_________________________
[| +   | |   Batteries   — |
|_____|_|_________________|
_________________________
| —  Type ‘#help;;’ | | + |]
|___________________|_|___|

Loading syntax extensions…
Camlp4 Parsing version 3.12.1

#

Попробуем выполнить нашу программу:

# #use «test.ml»;;
val string_of_list : (‘a -> string) -> ‘a list -> string = <fun>
val main : unit -> unit = <fun>
[1; 3; 5; 7; 9]
— : unit = ()

# main ();;
[1; 3; 5; 7; 9]
— : unit = ()

# #quit;;

Интерпретатор — это, конечно, здорово, но как нам скомпилировать программу, использующую батарейки? Тут в дело вступает OMake. Переходим в каталог с исходным кодом программы и выполняем команду:

omake —install

В результате будут созданы файлы OMakeroot и OMakefile. Первый можно оставить без изменений, а во второй следует прописать:

USE_OCAMLFIND = true

OCAMLPACKS[] +=
batteries.pa_comprehension.syntax
batteries.pa_string.syntax
batteries

OCAMLDEPFLAGS += -syntax camlp4o
OCAMLFLAGS += -syntax camlp4o

# имя программы
PROGRAM = test

# какие файлы компилируем
FILES[] =
test

OCamlProgram($(PROGRAM), $(FILES))

.DEFAULT: $(if $(BYTE_ENABLED), $(PROGRAM).run)
$(if $(NATIVE_ENABLED), $(PROGRAM).opt)

.PHONY: clean
clean:
rm -f
$(filter-proper-targets $(glob $(addsuffix .*, $(FILES))))
$(PROGRAM).run $(PROGRAM).opt

Еще раз проверяем, что не забыли прописать в исходном коде программы:

open Batteries_uni

… иначе при компиляции мы получите мистическую ошибку:

Error: Unbound value List.of_enum

Затем просто говорим omake и получаем исполняемый файл test.opt.

Что же делает omake? Давайте запустим его с флагом — -verbose и выясним:

*** omake: reading OMakefiles
*** omake: finished reading OMakefiles (0.01 sec)
— build . test.o
+ ocamlfind ocamlopt -package batteries.pa_comprehension.syntax,batteries.pa_string.syntax,batteries -warn-error A -syntax camlp4o -I . -c test.ml
— exit . test.o, 0.18 sec, code 0
— build . test.opt
+ ocamlfind ocamlopt -package batteries.pa_comprehension.syntax,batteries.pa_string.syntax,batteries -warn-error A -syntax camlp4o -I . -o test.opt test.cmx -linkpkg
— exit . test.opt, 0.33 sec, code 0
*** omake: done (0.53 sec, 0/1 scans, 2/4 rules, 4/61 digests)

Как видите, он выполняет две несложные команды. При желании мы можем поместить их в обычный Makefile или, скажем, некий скрипт, если у нас по какой-то причине аллергия на мейкфайлы.

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

Дополнение: См также решение задачи про игру «кошки-мышки» на OCaml .

EnglishRussianUkrainian