Научился использовать «батарейки»
11 февраля 2013
Помните, как в крайнем посте я обмолвился, что в OCaml есть генераторы списков, но для их получения нужно произвести дополнительные действия, и в результате использовал указатель на голову списка с циклами for? Настало время выяснить, что это за дополнительные действия такие.
Пример использования генераторов списков в OCaml:
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 ()
В действительности, конструкцию [? ... ?]
неправильно называть генератором списков, поскольку это генератор чего угодно. Например, так можно сгенерировать множество букв латинского алфавита:
Чтобы получить такое расширение синтаксиса, нам предстоит воспользоваться OCaml Batteries Included (или просто «батарейками»). Это поддерживаемый и развиваемый сообществом OCaml-программистов обширный набор хорошо документированных и согласованных между собой библиотек, а также расширений синтаксиса OCaml. Насколько я могу судить, в наши дни батарейки де-факто являются стандартной платформой для разработки программ на OCaml.
В Debian есть готовый пакет ocaml-batteries-included, который мы установили в прошлый раз. Также нам понадобится система сборки OMake:
Во FreeBSD, как обычно, все намного интереснее:
За неимением готового пакета, под FreeBSD батарейки придется собрать руками:
cd batteries-included
git checkout v1.5.0
gmake
Совсем недавно (25.01.13) вышли батарейки версии 2.0. Однако они зависят от bisect, который под FreeBSD также нужно собирать руками, предварительно забрав исходники из Darcs-репозитория. Думаю, на первое время вполне хватит проверенных временем батареек версии 1.5. Для их установки под рутом говорим:
gmake install-doc
Как в Debian, так и во FreeBSD, для использования батареек нам понадобится файл ~/.ocamlinit:
Если теперь запустить интерпретатор OCaml, мы должны увидеть примерно следующее:
_________________________
[| + | | Batteries - |
|_____|_|_________________|
_________________________
| - Type '#help;;' | | + |]
|___________________|_|___|
Loading syntax extensions...
Camlp4 Parsing version 3.12.1
#
Попробуем выполнить нашу программу:
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. Переходим в каталог с исходным кодом программы и выполняем команду:
В результате будут созданы файлы OMakeroot и OMakefile. Первый можно оставить без изменений, а во второй следует прописать:
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
Еще раз проверяем, что не забыли прописать в исходном коде программы:
… иначе при компиляции мы получите мистическую ошибку:
Затем просто говорим omake
и получаем исполняемый файл test.opt.
Что же делает omake? Давайте запустим его с флагом --verbose и выясним:
*** 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.
Метки: OCaml, Функциональное программирование.
Вы можете прислать свой комментарий мне на почту, или воспользоваться комментариями в Telegram-группе.