# Глава 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`.