Revised syntax – альтернатива классическому original syntax в OCaml. Он проще, регулярнее, логичнее, и исправляет некоторые недостатки оригинального синтаксиса, иногда вызывающие трудноуловимые баги. Этот синтаксис был назван "righteous", но название не прижилось.
Интерактивно: $ ocaml Objective Caml version 3.11.1
# #load "dynlink.cma";;
# #load "camlp4r.cma";;
Camlp4 Parsing version 3.11.1
# value test = do { (); 1 };
value test : int = 1
#
При компиляции вызовом ocamlc, ocamlopt или ocamlfind – добавьте
-pp camlp4r
в строку компиляции:
$ ocamlfind ocamlopt -pp camlp4r mymodule.ml -o myexecutable
При компиляции через ocamlbuild добавьте в файл _tags
тэг
camlp4r
для файлов, написанных в revised syntax, например,
<.ml> : camlp4r
Однако если добавлять тэг для всех *.ml*
, а в проекте есть
.ml-файлы, сгенерированные ocamllex/ocamlyacc (в original syntax), нужно
будет исключить их:
<mylexer.ml> | <myparser.ml{,i}> : -camlp4r, camlp4o
-
Точка с запятой завершает фразу. Двойная точка с запятой – не распознаётся. Последовательности операторов имеют другой синтаксис, и точка с запятой в конце фразы не будет перепутана с точкой с запятой, разделяющей последовательность операторов.
-
Объявление глобального значения производится ключевым словом
value
. Словоlet
зарезервировано исключительно для конструкцииlet..in
:Ocaml Revised let x = 23;;
let x = 23 in x + 7;;
value x = 23;
let x = 23 in x + 7;
-
В интерфейсах модулей вместо
val
следует использовать тожеvalue
.Ocaml Revised val x : int;;
value x : int;
-
Появился ещё один способ определить последовательность операторов: за ключевым словом
do
следует последовательность операторов, разделённых;
, окружённая{
и}
(допускается;
после последнего оператора).Ocaml Revised e1; e2; e3; e4
do { e1; e2; e3; e4 }
-
Тело
for
иwhile
может быть оформлено с тем же синтаксисом:Ocaml Revised while e1 do e2; e3; e4 done
while e1 do { e2; e3; e4 }
-
Скобки обязательны в туплах:
Ocaml Revised 1, "hello", World
(1, "hello", World)`
-
Списки всегда окружены
[
и]
. Их синтаксис:list ::= [ elem-list opt-cons ] elem-list ::= expression ; elem-list | expression opt-cons ::= :: expression | (empty)
-
Список – последовательность выражений, разделённых точкой с запятой, опционально завершённых
::
и выражением, и всё заключено в квадратные скобки. Например:Ocaml Revised x::y
[x::y]
[x; y; z]
[x; y; z]
x::y::z::t
[x::[y::[z::t]]]
x::y::z::t
[x; y; z :: t]
-
Заметьте, есть два способа записать последний случай.
Некоторые синтаксические конструкции используют понятие "irrefutable patterns". Сопоставление значений таким паттернам всегда успешно. Вот что может называться irrefutable pattern:
- Переменная.
- Символ
_
, соответствующий любому значению. - Конструктор тупла
()
. - Тупл с irrefutable patterns.
- Запись с irrefutable patterns.
- Irrefutable pattern с ограничением типа (type constraint).
Заметьте, что термин "irrefutable" применяется не ко всем паттернам,
сопоставление с которыми всегда удачно: например, тип с ровно одним
конструктором (кроме () : unit
) не является irrefutable.
-
Ключевое слово
function
больше не существует, используйтеfun
вместо него. -
При паттерн матчинге конструкций
fun
,match
иtry
все варианты должны быть заключены в квадратные скобки: открывающаяся скобка[
перед первым вариантом и закрывающаяся]
после последнего:Ocaml Revised match e with p1 -> e | p2 -> e2;;
match e with [ p1 -> e1 | p2 -> e2 ];
fun x -> x;;
fun [x -> x];
-
Однако, если вариант только один и паттерн является irrefutable, квадратные скобки не обязательны. Следующие примеры работают одинаково в оригинальном и revised синтаксисах:
Ocaml Revised fun x -> x
fun x -> x
fun {foo=(y, _)} -> y
fun {foo=(y, _)} -> y
-
Каррированный паттерн матчинг может быть оформлен через
fun
, но только с irrefutable паттернами:Ocaml Revised fun x (y, z) -> t
fun x (y, z) -> t
fun x y (C z) -> t
fun x y -> fun [C z -> t]
-
Теперь наконец-то стало возможно написать пустую функцию, кидающую исключение
Match_failure
, какой бы аргумент к ней ни применили, пустойmatch
, кидающийMatch_failure
после вычисления значения выражения, и пустойtry
, эквивалентный выражению безtry
:fun [] match e with [] try e with []
-
Паттерны в
let
иvalue
должны быть irrefutable. Следующее выражение, написанное в original syntax:let f (x::y) = ...
-
в revised syntax должно быть переписано так:
let f = fun [ [x::y] -> ...
-
Конструкция
where
вернулась, но только с одной привязкой: можно написатьe where x = y
, но неwhere x = y and z = t
-
Инструкция
<-
записывается как:=
:Ocaml Revised x.f <- y
x.f := y
-
Тип
ref
объявлен как запись с одним полемval
, вместоcontents
. Оператор!
более не существует, и присваивать значения ссылкам следует так же, как и любым другим изменяемым записям:Ocaml Revised x := !x + y
x.val := x.val + y
-
Конструкторы параметрических типов записываются перед параметрами, а параметры каррируются:
Ocaml Revised int list
list int
('a, bool) Hashtbl.t
Hashtbl.t 'a bool
type 'a foo = 'a list list;;
type foo 'a = list (list 'a);
-
В туплах из типов обязательны скобки:
Ocaml Revised int * bool
(int * bool)
-
В объявлении вариантного типа варианты должны быть заключены в квадратные скобки:
Ocaml Revised type t = A of i | B;;
type t = [ A of i | B ];
-
Возможно создать пустой (ненаселённый) тип, без конструктора:
type foo = [];
-
Существует разница между конструкторами с несколькими параметрами и конструкторами с одним параметром, являющимся туплом. При объявлении конструктора с несколькими параметрами они разделены ключевым словом
and
. В выражениях и при паттерн-матчинге параметры конструктора каррируются:Ocaml Revised type t = C of t1 * t2;;
type t = [ C of t1 and t2 ];
C (x, y);;
C x y;
-
Объявление конструктора с одним параметром-туплом осуществляется с использованием тупла типов. В выражениях и паттернах параметры не каррируются, а матчатся как обычный тупл:
Ocaml Revised type t = D of (t1 * t2);;
type t = [ D of (t1 * t2) ];
D (x, y);;
D (x, y);
-
Предопределённые конструкторы булевого типа
True
иFalse
начинаются с заглавной буквы, как любые другие конструкторы. -
В записях ключевое слово
mutable
должно быть после двоеточия:Ocaml Revised type t = {mutable x : t1};;
type t = {x : mutable t1};
-
Применение модулей теперь каррируется:
Ocaml Revised type t = Set.Make(M).t;;
type t = (Set.Make M).t;
Объявляются с указанием на открытость/закрытость типа:
type poly_open = [> `A | `B of (int * string) ]; type poly_eq = [= `A |`B of (int * string) ]; type poly_closed = [< `A | `B of (int * string) ];
Объекты объявляются с использованием
value
для полей:# object value my_field = 123; method my_method () = my_field; end; - : < my_method : unit -> int > = <obj>
-
Часть
else
теперь обязательна вif
:Ocaml Revised if a then b
if a then b else ()
-
Булевые операторы
or
иand
записываются только как||
и&&
:Ocaml Revised a or b & c
a || b && c
-
В файлах интерфейса labeled аргументы надо указывать с тильдой:
Ocaml Revised val f: x:int -> unit value f: ~x:int -> unit
-
Streams и паттерны в stream parsers окружаются
[:
и:]
вместо[<
and>]
. -
Компонент stream'а записывается с обратным апострофом вместо обычного:
Ocaml Revised [< '1; '2; s; '3 >]
[: \`1; \`2; s; \`3 :]
-
Варианты в парсере заключаются в
[
and]
, как вfun
,match
иtry
. Если вариант только один, скобки не обязательны:Ocaml Revised parser [< `Foo >] -> e | [< p = f >] -> f
parser [ [: `x :] -> x ]
parser [< 'x >] -> x
parser [: `x :] -> x
-
Возможно написать пустой парсер, кидающий исключение
Stream.Failure
, какой бы поток к нему ни применили. Пустой паттернг матчинг тоже кидаетStream.Failure
:parser [] match e with parser []
2011-03-26 13:08
-