Permalink
Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
821 lines (589 sloc) 18.1 KB

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 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 and parsers

    • Streams и паттерны в stream parsers окружаются [: и :] вместо [< and >].

    • Компонент stream'а записывается с обратным апострофом вместо обычного:

      Ocaml Revised
        [&lt; '1; '2; s; '3 &gt;]
      
        [: \`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