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


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




[23]

(a + ib) - (c + id) = (a - c) + i(b - d) (a + ib) * (c + id) = (ac - bd) + i(ad + bc)

, .. (ac + bd) + i(bc - ad) (a + ib)/(c + id) =-c2 + d2-

Абстракция является более гибкой по сравнению с абстрактными типами данных в одних случаях и менее гибкой в других. Большая гибкость проистекает из того, что абстракция не обязана быть "типом данных с операциями", как это вытекает из самой формы абстрактных типов. Например, может быть не объявлено ни одного типа вообще, а объявленные типы не обязаны быть рекурсивными типами. Абстрактные типы данных несколько более гибки потому, что они, являясь обычной формой объявления, могут появляться везде, где могут появляться объявления, - в то время как абстракции могут появляться лишь там, где могут появляться структуры: на верхнем уровне или в инкапсулированных объявлениях. Это ограничение не кажется существенным, поскольку обычно типы определяются на верхнем уровне4.

3.4 Функторы

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

-signature SIG =

sig type t

val eq : t*t -> bool end;

-functor F( P : SIG ) : SIG =

type t = P.t * P.t

fun eq((x,y),(u,v)) = P.eq(x.u) andalso P.eq(y.v)

4 Мы рекомендуем при программировании на ML избегать абстрактных типов данных, поскольку в дальнейшем они могут быть устранены из языка (так как абстракция достаточна для их замены).


3.4. ФУНКТОРЫ

>functor F( P : SIG ) : SIG

Сигнатура SIG определяет тип t и бинарное отношение eq. Функтор F определяет функцию, которая, получив структуру, сопоставимую с сигнатурой SIG, вырабатывает другую структуру (которая в данном примере также должна быть сопоставима с сигнатурой SIG - однако, разумеется, в других случаях сигнатура структуры-результата не обязана совпадать с сигнатурой структуры-параметра).

Функторы применяются к структурам и вырабатывают другие структуры.

-structure S : SIG =

type t = int

val eq : t*t->bool = op = end;

>structure S =

type t = int

val eq = fn : t*t->bool end

-structure SS : SIG = F(S);

>structure SS =

type t = int*int

val eq = fn : t*t->bool end

Здесь мы создали структуру S, сопоставимую с сигнатурой SIG. Функтор F, применяемый к структуре S, строит новую структуру с той же сигнатурой - но в которой t уже является типом упорядоченных пар целых чисел, а функция равенства определена на этих парах. Обратите внимание на то, как SS строится из S с помощью функтора F.

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

-structure Т : SIG =

type t = string * int

val eq : t*t->bool = op =

fun f(x:t) = (x,x) end;

>structure T =


type t = val eq :

string * int t*t->bool

- structure TT : SIG = F(T); > structure TT = struct

type t = (string*int)*(string*int) val eq : t*t->bool

Хотя и имеется ограничение, что функтор должен иметь ровно один аргумент, оно не является существенным: при необходимости несколько структур могут быть включены в одну как подструктуры, и затем эта структура может быть передана функтору. На практике это обычно не создает никаких неудобств, поскольку в тех случаях, когда несколько структур должны быть переданы в качестве аргумента функтору, они, как правило, настолько тесно связаны между собой, что имеется много других причин, по которым их разумно объединить в одну структуру. Функторы должны подчиняться тому же (рекомендательному) правилу замкнутости, что и сигнатуры: они не должны содержать открытых ссылок на значения, типы и исключения во внешней среде (за исключением предопределенных системных примитивов). В теле функтора без всяких ограничений могут использоваться ссылки на параметр и его компоненты (с использованием уточняющих имен), на локальные идентификаторы и на ранее определенные функторы и сигнатуры.

Тело функтора не обязано представлять из себя инкапсулированные объявления (хотя, вероятно, это наиболее распространенный случай). В теле функтора могут свободно использоваться составные имена и аппликации функторов (однако важный момент: функтор не может быть рекурсивным!). Приведем примеры:

- functor

= F(F(P));

> functor

- functor

> functor

Нужно отметить, что функтор I не является тождественным: если S есть структура, сопоставимая с сигнатурой SIG, но с большим количеством компонент, чем упомянуто в сигнатуре, то F(S) будет "урезанной" по сравнению с S. Например:

- structure S = struct

type t = int



[стр.Начало] [стр.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]