Слайд 1Синонимы в сопоставлении с образцом
Ключевое слово as
match [1;2;3] with e1::( (e2::tail2)
as tail1) -> …
Позволяет избежать лишнего сопоставления с образцом, как, например, в
match [1;2;3] with e1::tail1 -> …
match tail1 with e2::tail2 -> …
Слайд 2Условия в сопоставлении с образцом
Ключевое слово when
let rec remove_duplicates = function
(*
работает на отсортированном списке *)
| [] -> []
| [x] -> [x]
| e1::e2::tail when e1 == e2 ->
e1::(remove_duplicates tail)
| e::tail -> e::(remove_duplicates tail)
В OCAML нельзя писать
| e::e::tail -> …
Слайд 3Интервалы в сопоставлении с образцом
| ‘A’..’Z’ -> “заглавная буква”
Слайд 4Синтаксис языка OCAML
Кортеж (tuple)
Кортеж есть упорядоченный набор объектов языка возможно различного
типа
(1, 2, 3.14, “abc”, [4; 5], (6, 7), 8)
Сравнение кортежа и списка
Тип объектов
В кортеже: произвольный
В списке: один и тот же
Размер
Для кортежа: фиксированный
Для списка: переменный
Слайд 5Кортеж и сопоставление с образцом
В сопоставлении с образцом кортеж указывается «полностью»:
match
(1, “a”, 2, “b”, 3)
with (x, _, y, _, 3) -> printf “got x = %d, y = %d\n” x y
Теоретически и практически кортеж аналогичен «записям» и «структурам» ИП.
Удобнее тем, что не нужно описывать типы компонент и давать им имена
Кортеж – «запись» ad hoc
Слайд 6Кортежи и функции
В OCAML все функции – каррированные:
fun x y ->
x + y тождественно равно
function x -> function y -> x + y
Кортеж позволяет задать «традиционную» (некаррированную) функцию нескольких аргументов:
function (x, y) -> x + y
На практике это имеет смысл только в тех случаях, когда кортеж аргументов представляет собой осмысленное целое.
Например, координаты точки на поверхности:
function (x0, y0) (x1, y1) -> abs(x1-x0) + abs(y1-y0)
Слайд 7Кортеж и сопоставление с образцом, 2
let rec addlists list1 list2 =
match
list1, list2 with
| [], list2 -> list2
| list1, [] -> list1
| h1::list1, h2::list2 -> (h1+h2)::(addlists list1 list2)
Слайд 8Записи (records)
Запись – это кортеж, в котором компоненты идентифицируются именем, а
не позицией в кортеже.
Запись невозможно задать ad hoc.
Требуется описание типа.
type имя_типа = { имя_поля1: тип_поля1; …; имя_поляN: тип_поляN }
Базовые типы объектов: int, string, float, char, bool
Пример:
type shopping_cart = {item_id: string; quantity: int}
Сравнимо с С:
struct shopping_cart { char *item_id; int quantity; }
Слайд 9Записи и сопоставление с образцом
«Конструктор» записи:
{item_id: “battAA”; quantity: 4}
Сопоставление с образцом:
let
check_max_quantity cart =
match cart with
{ item_id = id; quantity = q} -> q < 10
let getQuantity { quantity = q } -> q
Имя типа не указывается ни в конструкторе, ни при сопоставлении с образцом
Поэтому имена полей должны быть уникальны в пределах модуля
{name: string, salary: float} и {name: string, engine_power: float }
Слайд 10Вариантные типы
type street_light = Red | Yellow | Green
type length =
In of float | Cm of float
let length_sum 1l, l2 ->
| In i1, In i2 -> In (i1 +. i2)
| Cm c1, Cm c2 -> Cm (c1 +. c2)
| In i1, Cm c2 -> Cm (i1 /. 2.54 +. c2)
| Cm c1, In i2 -> Cm (c1 +. i2 /. 2.54)
Типы в of ___ не обязаны быть одинаковыми.
Аналог union и enum C++
Слайд 11Кортежи и описания типов
type silly_dist_type = Meters of float | FtIn
of (int * float)
let my_meters = Meters 5.73;;
let my_fts = FtIn (18, 9.59);;
type time = Time of (int * int * float);; (* ч. мин. сек. *)
Слайд 12Параметрический полиморфизм
type ‘t mytree = Leaf of ‘t | Branch of
(‘t mytree * ‘t mytree);;
«Конструктор» записи:
{item_id: “battAA”; quantity: 4}
Сопоставление с образцом:
let check_max_quantity cart =
match cart with
{ item_id = id; quantity = q} -> q < 10
let getQuantity { quantity = q } -> q
Имя типа не указывается ни в конструкторе, ни при сопоставлении с образцом
Поэтому имена полей должны быть уникальны в пределах модуля
{name: string, salary: float} и {name: string, engine_power: float }
Слайд 13Типы функциональных значений
let sum x y = x + y;;
sum :
int -> int -> int
let rec length = function
| [] -> 0
| _::list -> 1 + length list;;
length : 'a list -> int