Ремонт принтеров, сканнеров, факсов и остальной офисной техники


назад Оглавление вперед




[5]

Объявление х является локальным и поэтому невидимо за пределами приведенной конструкции. Тело конструкции let (располагающееся между ключевыми словами in и end) вычисляется в среде, полученной в результате вычисления объявлений, расположенных перед in. В приведенном примере, расположенное там объявление привязывает идентификатор х к значению 10. В полученной среде значение выражения х*х+2*х+1 есть 121; это значение и будет значением всего выражения.

Упражнение 2.3.1 Какой результат будет напечатан МЬ-системой в ответ на ввод следующих объявлений (предполагается, что нет никаких других привязок для х, у и z):

1.val х=2 and у=х+1;

2.val х=1; local val х=2 in val y=x+l end; val z=x+l;

3.let val x=l in let val x=2 and y=x in x+y end end;

2.4 Образцы

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

Предположим, что х имеет тип int*bool. Тогда х является парой, левая компонента которой является целым, а правая - логическим. Мы можем получить значения левой и правой компонент, используя следующую обобщенную форму привязки к значению:

-val х = (17, true);

>val х = (17,true) : int*bool

-val (left, right) = x;

>val left = 17 : int val right = true : bool

Левая часть второй привязки является образцом. В общем случае образец строится из переменных и констант с помощью конструкторов. Таким образом, образец есть выражение, возможно, включающее переменные. Отличие от ранее рассматривавшихся выражений состоит в том, что в образце переменные не изображают значения определенные предшествующими привязками, а являются переменными, которые должны быть привязаны к значениям в процессе сопоставления с образцом. В


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

Обратите внимание на то, что простейшим случаем образца является переменная. Таким образом, рассмотренная ранее привязка является частным случаем сопоставления с образцом.

Бессмысленно пытаться сопоставить, например, целое с упорядоченной парой или список с записью. Поэтому любая такая попытка рассматривается как ошибка в согласовании типов, и обнаруживается статически, т.е. в период компиляции. Однако, сопоставление с образцом может потерпеть неудачу и динамически, т.е. во время исполнения программы:

-val х = (false, 17);

>val х = (false,17) : bool*int

-val (false, w) = x;

>val w = 17 : int

-val (true, w) = x; Failure: Match

Обратите внимание на то, что во второй и в третьей привязке образец содержит константу в качестве левого члена упорядоченной пары. Только пара с таким же значением левого члена может быть успешно сопоставлена с таким образцом. Во втором случае это условие выполнено, и сопоставление завершается успешно, привязывая идентификатор w к значению 17. В последнем же случае условие не выполнено; сообщение Failure: Match говорит о том, что в период исполнения возникла ошибка при сопоставлении с образцом.

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

-val 1st = [ "Lo", "and", "behold" ];

>val 1st = [ "Lo", "and", "behold" ]: string list

-val [xl,x2,x3] = 1st

>val xl = "Lo" : string val x2 = "and" : string val x3 = "behold" : string


Это работает прекрасно - до тех пор, пока мы знаем длину списка. Но как быть в случае непустого списка 1st произвольной длины? Ясно, что его невозможно разложить на компоненты с помощью одного фиксированного образца! Тем не менее, мы можем разложить 1st, опираясь на индуктивное определение списка.

-val 1st = [ "Lo", "and", "behold" ];

>val 1st = [ "Lo", "and", "behold" ]: string list

-val hd :: tl = 1st;

>val hd = "Lo": string

val tl = ["and"."behold"]: string list

Здесь hd привязывается к значению первого элемента списка 1st (называемого головой (head) списка 1st) и tl привязывается к списку, получающемуся после удаления первого элемента из 1st (этот список называется хвостом (tail) списка 1st). Типом hd является string, а типом tl - string list. Причина этого в том, что конструктор : : требует в качестве левого аргумента элемент списка, а в качестве правого - список.

Упражнение 2.4.1 Что произойдет, если мы напишем [hd,tl]=lst

вместо того, что было написание выше? (Подсказка: Замените сокращение [hd.tl] полной записью.)

Предположим, что нас интересует только голова списка. Тогда нам незачем приписывать имя хвосту (с единственной целью немедленно его забыть). Чтобы избавиться от необходимости выдумывать имена, которые в дальнейшем все равно не будут использоваться, ML позволяет писать вместо них универсальный образец, или джокер (обозначаемый знаком " " - подчеркивание), который может быть сопоставлен с любым значением без привязки к нему идентификатора.

-val 1st = [ "Lo", "and", "behold" ];

>val 1st = [ "Lo", "and", "behold" ] : string list

-val hd :: = 1st;

>val hd = "Lo" : string

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

-val г = {name="Foo", used=true};

>val г = {name="Foo",used=true} : {name:string,used:bool}

-val { used=u, name=n } = r;

>val n = "Foo" : string val u = true : bool



[стр.Начало] [стр.1] [стр.2] [стр.3] [стр.4] [стр.5] [стр.6] [стр.7] [стр.8] [стр.9] [стр.10] [стр.11] [стр.12] [стр.13] [стр.14] [стр.15] [стр.16] [стр.17] [стр.18] [стр.19] [стр.20] [стр.21] [стр.22] [стр.23] [стр.24] [стр.25] [стр.26] [стр.27] [стр.28] [стр.29] [стр.30] [стр.31] [стр.32]