Глава
                        1
                          Глава
                        2
                          Глава
                        3
                          Глава
                        4
                          Глава
                        5
                          Глава
                        6
                          Глава
                        7
                          Глава
                        8  navigation 
                          Глава
                        10
                          Глава
                        11
                          Глава
                        12
                          Глава
                        13
                          Глава
                        14 

Глава 9. Интерактивная система (ocaml)

В этой главе описывается интерактивная система Objective Caml, преднзначенная для использования языка в циле чтения-компиляции-вызова. В этом режиме система считывает фразы Caml из ввода, проверяет тип, компилирует и выполняет и, а затем выводит распознанный тип и значение результата, если он есть. Перед чтением каждой фразы система выводит символ # (диез).

Ввод может занимать несколько строк. Он заканчивается ;; (двумя точками с запятыми) и состоит из одной или нескольких фраз со следующим синтаксисом:

toplevel-input ::= { toplevel-phrase } ;;
toplevel-phrase ::= definition
| expr
| # ident directive-argument
definition ::= let [ rec ] let-binding { and let-binding }
| type-definition
| exception-definition
| module module-name ( : module-type ) = module-expr
| module type modtype-name = module-type
| open module-path
| external value-name : typexpr=external-decalaration
| type-definition
| exception-definition
directive-argument ::= nothing
| string-literal
| integer-literal
| value-path

Фраза состоит из определений, подобных тем, что включаются в реализации единиц компиляции, или в выражениях модулей struct ... end. Определение связывает имена значений, имена типов, исключения, имена модулей и имена типов модулей. Интерактивная система осуществляет само связывание и выводит определенные типы и значения, если они есть.

Кроме того, фраза может содержать директиву open (см. раздел 6.11) или выражение (см. раздел 6.7). Выражение вычисляется без связывания, и система выводит его результат.

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

UNIX

Интерактивная система запускается командой ocaml:

ocaml options objects # интерактивный режим
ocaml options objects scriptfile # пакетный режим

Опции описаны ниже. Параметр objects включает имена файлов с расширениями .cmo или .cma - интерпретатор загружает их сразу после установки опций. Параметр scriptfile - это любое имя файла без расширения .cmo или .cma.

Если параметр scriptfile отсутствует в командной строке, система запускается в интерактивном режиме - фразы читаются из стандартного ввода, результаты выводятся в стандартный вывод, ошибки - в стандратный поток ошибок. Знак конца файла в стандартном вводе останавливает ocaml (см. также директиву #quit в разделе 9.2).

При запуске, но до чтения первой фразы, из текущего каталога считывается файл .ocamlinit (если он есть). Его содержимое читается как последовательность фраз OCaml и выполняеся как в при использовании директивы #use. При вычислении эти фразы не выводятся.

Интерактивная система не редактирует строки, однако ее легко можно использовать в комбинации с внешним редактором строк типа fep командой fep -emacs ocaml или fep -vim ocaml. Кроме того, ocaml может запускаться в GNU Emacs, что позволяет использовать все возможности этого редактора (см. подкаталог emacs в дистрибутиве Objective Caml).

Анализ, компиляция и выполнение текущей фразы в любой момент могут быть прерваны клавишами ctrl-c (или, если точнее отправкой сигнала sigintr процессу ocaml). Интерактивная система в этом случае немедленно возвращается к приглашению #.

Если в командной строке задан параметр scriptfile, интерактивная система переходит в режим сценария: содержимое файла считывается как последовательность фраз Objective Caml и выполняется как при использовании директивы #use(раздел 9.2). Результаты компиляции не выводятся. По окончании файла работа команды caml завершается. Команды из стандартного ввода не читаются. Sys.argv модифицируется, причем все параметры Objective Caml игнорируются, а в Sys.argv.(0) помещается имя файла сценария.

Если первая строка файла сценария начинается с символов #!, она пропускается. Таким образом, теоретически возможно делать файлы сценариев исполняемыми и помещать в первую строку что-то вроде #! /usr/local/bin/ocaml. Однако в большинстве инсталляций команда ocaml сама является сценарием командной оболочки, а операционные системы Unix как правило не умеют работать с вложенными сценариями.

Windows

Кроме команды текстового режима ocaml, которая работает точно так же, как и под Unix, существует графический интерфейс интерактивной системы. Он называется ocamlwin.exe и может запускаться как из файлового менеджера, так и из оболочки Windows.

Окно "Terminal" разделено на две области. В нижней вводятся и редактируются фразы, верхняя содержит копию ввода и вывод интерпретатора. Клавиша "Return" пересылает ввод интерпретатору, клавиша "Enter" просто добавляет символ новой строки (назначение клавиш конфигурируется в меню "Preferences").

Содержимое окна ввода может быть изменено в любой момент через стандартный интерфейс Windows. В отдельном окне показаны ранее введенные фразы.

Для выхода из приложения Ocamlwin используется либо пункт меню File|Exit, либо функция quit, описанная ниже.

Анализ, компиляция и выполнение текущей фразы в любой момент могут быть прерваны командой меню Interrupt Objective Caml. Интерактивная система в этом случае немедленно возвращается к приглашению #.

9.1 Опции

ocaml распознает следующие опции командной строки:

-I directory

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

Если перед directory стоит знак +, путь берется относительно стандартной библоитеки. Например, -I +labltk добавит к пути поиска подкаталог labltk каталога стандартной библиотеки.

Кроме того, каталоги можно добавить к пути поиска непосредственно после запуска интрепретатора директивой #directory.

-nolabels

Игнорировать обязательные метки в типах. В этом случае метки не могут использоваться в приложениях, и порядок аргументов становится строгим.

-principal

Во время проверки типов компилятор проверяет также информацию о путях, следя чтобы все типы выводились приниципально, Программы, допустимые в режиме -principal, допустимы и в режиме по умолчанию с эквивалентными типами.

-rectypes

Разрешает во время проверки типа произвольные рекурсивные типы. По умолчанию поддерживаются только рекурсивные типы с рекурсией по типу объекта.

-unsafe

См. описание соответствующей опции ocamlc в гл. 8. Отключает проверку границ на массивах и обращении к строкам (конструкции v.(i) и s.[i]). Программы, собранные с этой опцией несколько быстрее, но не являются безопасными: при обращении к элементу за пределами массива или границы строки может произойти все, что угодно.

-w warning-list

Включает или выключает предупреждение в соответствие со значением аргумента warning-list.

Unix

Проверяются также следующие переменные среды:

LC_CTYPE

Если эта переменная установлена в значение iso8859-1, знаки с акцентам из набора Latin-1 в строках и символьных литералах выводятся как есть. В противном случае они печатаются десятичными контрольными последовательностями (вида \ddd).

TERM

При выводе сообщений об ошибках интерпретатор пытается визуально подчеркивать место обнаружения ошибки. Он проверяет переменную окружения TERM, чтобы определить тип терминала и выяснить его возможности в базе данных терминалов.

9.2 Директивы

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

Обратите внимание: все директивы начинаются со знака # (диез). Он должен печататься перед директивой, но его не следует путать с приглашением интрепретатора. Если, например, напечатать #quit;;, работа интерпретатора завершится, ввод же quit;; приведет лишь к ошибке "unbound value quit".

#quit;;

Завершает работу интерпретатора ocaml.

#labels bool;;

Игнорирует метки в типах функций, если аргумент установлен в false, либо переключает в режим по умолчанию (коммутирующий), если аргемент установлен в true.

warnings "warnings-list";;

Включает или выключает предупреждения согласно значению аргумента.

#directory "dir-name";;

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

#cd "dir-name";;

Изменяет текущий каталог.

#load "file-name";;

Загружает в память байткод из объектного файла (.cmo), созданного компилятором ocamlc.

#use "file-name";;

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

#install-printer printer-name;;

Эта директива регистрирует функцию printer-name в качестве принтера для значений, типы которых совпадают с типом аргумента функции. Иными словами, интерактивная система будет вызывать printer-name, как только ей потребуется вывести подобное значение.

Функция должна иметь тип Format.formatter ->t-> unit, где t - тип значения, и выводить строковое представление значения типа t на заданном форматировщике с помощью функций библиотеки Format. Из соображений обратной совместимости функция должна также иметь тип t-> unit и предоставлять вывод для стандартного форматировщика, но такое использование считается устаревшим.

#remove-printer printer-name;;

Удаляет указанную функцию из таблицы принтеров.

#trace function-name;;

После выполнения этой директивы все вызовы функции function-name будут "трассироваться" - аргументы и результаты, а также исключения, возбужденные либо самой функией, либо вызываемой ей функцией, печатаются при каждом ее вызове. Если функция является производной, каждый аргумент печатается так, будто он передается функции.

#untrace function-name;;

Останавливает трассировку указанной функции.

#untrace_all;;

Останавливает трассировку всех функций.

#print_depth n;;

Ограничивает вывод значений максимальной глубиной n. Части значений с глубиной, превосходящей n выводятся как ... (многоточие).

#print_length n;;

Ограничивает количество узлов выводимых значений максимальным числом n. Оставшиеся части выводятся как ... (многоточие).

9.3 Интерпретатор и система модулей

Фразы в интерактивной системе могут ссылаться на идентификаторы, определенные в единицах компиляции точно так же, как и в отдельных единицах компиляции - либо по полным именам (Modulename.localname), либо с помощью конструкции open и неполного имени (см. раздел 6.3).

Однако реализация единицы, на имена котрой предполагается ссылаться уже должна быть загружена в память. При запуске интерактивная система включает все реализации модулей стандартной библиотеки, а реализации пользовательскиз модулей загружаются директивой #load, описанной выше. Ссылка на единицу, реализации которой не найдено, приведет к ошибке "Reference to undefined global `...'".

Обратите внимание, что фраза open mod всего лишь обеспечивает доступ к компилированному интерфейсу (.cmi) модуля mod, не загружая его реализации и не сообщая об ошибке, если она не будет найдена. Ошибка "reference to undefined global mod" возникает только в том случает, если выполняется значение или определение модуля, ссылающегося на mod.

9.4 Распространенные ошибки

В этом разделе описываются наиболее распространенные сообщения об ошибках.

Cannot find file filename

Указанный файл не обнаружен в текущем каталоге или каталогах, входящих в пусть поиска.

Если filename представлен в формате mod.cmi, то это означает, что обнаружена ссылка на модуль mod, который еще не скомпилирован. Чтобы исправить эту ошибку, достаточно скомпилировать предварительно файл mod.mli или mod.ml.

Если filename представлен в формате mod.cmo, то это означает, что обнаружена попытка загрузить директивой #load несуществующий файл с байткодом. Чтобы исправить ошибку, надо скомпилировать файл mod.ml.

Если программа включает несколько каталогов, они могут не попасть в пусть поиска. В таком случае их надо добавить директивой #directory.

This expression has type t1, but is used with type t2

См. раздел 8.4.

Reference to undefined global mod

Реализаци модуля не загружена директивой #load. См. раздел 9.3.

9.5 Заказные интерпретаторы

Команда ocamlmktop создает интерпретаторы Objective Caml, котрые загружат при запуске пользовательский код.

Она принимает в качестве аргумента набор файлов .cmo и .cma и компонует их с объектными файлами, реализующими интреактивную систему Objective Caml. Типичный пример:

ocamlmktop -o mytoplevel foo.cmo bar.cmo gee.cmo

Здесь создается файл с байткодом mytoplevel, включающий интерактивную систему Objective Caml и код из трех файлов .cmo. Этот файл уже является исполняемым и запускается так:

./mytoplevel

В результате загружается обычный интерпретор, однако код из foo.cmo, bar.cmo и gee.cmo уже находится в памяти, словно были введены директивы

#load "foo.cmo";;
#load "bar.cmo";;
#load "gee.cmo";;

Впрочем, модули Foo, Bar и Gee не открыты, поэтому надо ввести

open Foo;;

если это потребуется.

9.6 Опции ocamlmktop

Команда ocamlmktop допускает следующие опции командной строки:

-cclib libname

Передает компоновщику С опцию -llibname при компоновке в "заказном" режиме. См. описание соответствующей опции ocamlc в гл. 8.

-ccopt option

Передает указанные опции компилятору и компоновщику С при компоновке в "заказном" режиме. См. описание соответствующей опции ocamlc в гл. 8.

-custom

Компоновка в "заказном" режиме. См. описание соответствующей опции ocamlc в гл. 8.

-I directory

Добавяет указанную директорию к списку директорий, в которых ищутся компилированные файлы (.cmo и .cma).

-o exec-file

Задает имя файла интерпретатора, создаваемого компоновщиком. По умолчанию это a.out.