Mercury (язык программирования)

Материал из Национальной библиотеки им. Н. Э. Баумана
Последнее изменение этой страницы: 11:36, 2 июня 2016.
Mercury
Mercury (programming language) logo.jpg
Парадигма Функционально-логическое программирование
Спроектировано Zoltán Somogyi
Первый   появившийся 1995
Стабильная версия 14.0.01 / 14 сентября 2014
Печать дисциплины Строгая, Статическая
Портал: https://www.mercurylang.org/

Mercury — язык функционально-логического программирования со строгой типизацией. Синтаксис Mercury частично унаследован от Пролога, система типов похожа на Haskell. Это чисто декларативный язык, разработчики полностью убрали из него все императивные возможности, что позволило улучшить встроенные в компилятор возможности оптимизации. Название Mercury дано в честь бога скорости Меркурия и отражает направленность на получение быстродействующих программ. Операции, при реализации которых обычно отказываются от чисто декларативного подхода, такие как ввод-вывод, выражаются в Mercury с помощью декларативных конструкций, используя линейные типы. Язык разработан в Мельбурнском университете. Первую версию выпустили Fergus Henderson, Thomas Conway и Zoltan Somogyi 8 апреля 1995 года.

Цели

Декларативное программирование (например, на Prolog) всегда было очень мощным. Однако, создание крупного программного обеспечения нелегко. Мы стремимся, чтобы сделать программирование в целом проще:

  • программы больше
  • команды больше
  • надежность программы лучше
  • программы эффективнее

Синтаксис

Разрешенные объявления:

 :- type
 :- solver type
 :- pred
 :- func
 :- inst
 :- mode
 :- typeclass
 :- instance
 :- pragma
 :- promise
 :- initialise
 :- finalise
 :- mutable
 :- module
 :- interface
 :- implementation
 :- import_module
 :- use_module
 :- include_module
 :- end_module

Объявления ‘type’, ‘pred’ and ‘func’ используются для системы типизации, объявления ‘inst’ and ‘mode’ - для системы режимов, декларации ‘pragma’ - для интерфейса других языков, для подсказок компилятору о встраивании, а остальные предназначены для системы модулей.

Функция - это объект вида ‘Заголовок = Результат’. Предикат - это объект вида ‘Заголовок’, где функтор верхнего уровня заголовка - не :-/1, :-/2, -->/2 или =/2. В обоих случаях заголовок не должен быть переменной.

Правило - это объект вида ‘Заголовок = Результат :- Тело’ или ‘Заголовок :- Тело’, где функтор верхнего уровня заголовка - не =/2. В обоих случаях заголовок не должен быть переменной. Функтор верхнего уровня заголовка определяет, к какому предикату или функции он относится; предикат или функция должны быть объявлены с предшествующим объявлением ‘pred’ or ‘func’ в этом модуле.

Переменные состояния

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

 main(IO0, IO) :-
 io.write_string("The answer is ", IO0, IO1),
 io.write_int(calculate_answer(...), IO1, IO2),
 io.nl(IO3, IO).

а пользуясь синтаксисом переменных состояния

 main(!IO) :-
 io.write_string("The answer is ", !IO),
 io.write_int(calculate_answer(...), !IO),
 io.nl(!IO).

Переменная состояния записывается как ‘!.X’ или ‘!:X’, обозначая “текущее” или “следующее” значение последовательности, помеченное X. Аргумент ‘!Х’ является сокращением для двух аргументов переменной состояния ‘!.Х, !:Х’; то есть ‘p(..., !Х, ...)’ анализируется как ‘p(..., !.Х, !:Х, ...)’. В пределах каждого параграфа, transform преобразует переменные состояния в последовательности простых логических переменных. Синтаксические преобразования описывается в терминах понятийной "transform’ функции. Преобразование применяется один раз для каждой переменной состояния X с некоторыми свежими переменными, которые мы будем называть ThisX и NextX.

Например, следующее предложение используя лямбда-выражение

 p(A, B, !S) :-
         F = (pred(C::in, D::out, !.S::in, !:S::out) is det :-
                 q(C, D, !S)
         ),
         ( F(A, E, !S) ->
              B = E
         ;
              B = A
         ).

Типы

Mercury имеет строгую статическую типизацию, похожую на Haskell.

Определенные типы являются встроенными или определенными в библиотеке Mercury:

  • Примитивные типы: char, int, float, string. Существует специальный синтаксис для констант типа int, float, and string. (Для char используется обычный синтаксис.)
  • Предикаты: pred, pred(T), pred(T1, T2)
  • Функции: (func) = T, func(T1) = T
  • Кортежи: {}, {T}, {T1, T2}
  • Универсальный тип 'univ'

И все типы из Prolog-а.

Разработчики легко могут определить свои типы:

 :- type playing_card
     ---> normal_card(
              c_suit :: suit,
              c_num :: int
          )
     ;    joker.
 :- type suit
     ---> heart
     ;    diamond
     ;    spade
     ;    club.

Типы аргументов предикатов определены в объявлении pred.

 :- pred fibs(int, int).
 fibs(N, F) :-
      ( N < 2 ->
          F = 1
      ;
          fibs(N - 1, FA),
          fibs(N - 2, FB),
          F = FA + FB
      ).

Режимы

Режим предиката или функции, - это отображение из исходного состояния экземпляра аргументов предиката, или аргументов и результата функции, в их конечное состояние экземпляра. Для описания состояний экземпляров, мы используем информацию, предоставляемую системой типов. Типы могут рассматриваться как обычные деревья с двумя типами узлов: или-узлы, представляющие типы и и-узлы, представляющие конструкторы. Дети или-узлов являются конструкторами, которые могут быть использованы для создания условия нужного типа; дети и-узла являются типами аргументов конструкторов. Мы добавляем больше информации в или-узлах деревьев типа.

Когда инстанцированное дерево говорит нам, что переменная связывается, может быть несколько альтернативных функциональных символов, к которому она может быть привязана. В инстанцированное дерево не сообщит нам, с чем он связан; вместо этого для каждого возможного символа функции говорит нам, какие именно аргументы символа функции будут свободными, а какие будут связанными. Тот же принцип применяется рекурсивно для этих аргументов связи. Система режимов Mercury позволяет пользователям объявлять имена для инстанцированных деревьев с помощью деклараций, таких как

 :- inst listskel == bound( [] ; [free | listskel] ).

Режим объявления предиката назначает режим сопоставления для каждого аргумента предиката. Режим объявления функции назначает режим сопоставления для каждого аргумента функции и режим сопоставления сопоставления результату функции. Каждый режим предиката или функции называется процедурой. Например:

 :- mode out_listskel ==
 free >> listskel.
 :- mode in_listskel ==
 listskel >> listskel.

тип и режим объявления функции и предиката задается следующим образом:

 :- func length(list(T)) = int.
 :- mode length(in_listskel) = out.
 :- mode length(out_listskel) = in.
 :- pred append(list(T), list(T), list(T)).
 :- mode append(in, in, out).
 :- mode append(out, out, in).

Детерминизм

Для каждого режима предиката или функции мы подразделяем режим в зависимости от того, сколько раз он может достигнуть цели, и может ли он потерпеть неудачу, прежде чем произведет свое первое решение. Если все возможные вызовы для конкретного режима предиката или функции, которые возвращают вызывающему (вызовы, которые завершаются, не бросают исключение и не вызывают фатальные ошибки во время выполнения):

  • имеют ровно одно решение, то этот режим детерминирован (det);
  • имеют 0 или одно решение, то этот режим полудетерминирован (semidet)
  • имеют 1 решение или больше, то этот режим множества решений (multi)
  • имеют 0 или больше решений, то этот режим недетерминирован (nondet)
  • падают, не получив решения, то у этого решения есть детерминизм или ошибка.

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

Смотри также

Mercury