Главная » Haskell » Абстракция  данных при помощи модулей

0

Абстрактным типом данных называют такой тип,  который  предоставляет для работы с элементами этого типа определённый набор функций, а также возможность создавать элементы этого типа при  помощи специальных функций. Вся внутренняя структура такого типа спрятана от разработчика  программного  обеспечения — в этом и заключается суть абстракции. Абстрактный тип данных определяет набор независимых от конкретной реализации типа функций для оперирования его значениями.

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

Между абстрактными типами данных и структурами данных, которые реализуют абстрактные типы, существует очень тонкое  различие, которое  иногда некоторые программисты уловить не могут. Например, такой абстрактный тип данных, как список List(A), может  быть реализован при помощи массива, линейного списка той или иной направленности и т. д. Однако над списком List(A) определён набор функций, который будет работать всегда, независимо от того, как сам список реализован.

Педантичный читатель спросит: «Причём же здесь модули?» Действительно, в какой-то мере абстракция данных уже рассмотрена в должной мере в предыдущей главе справочника. Однако остаётся рассмотреть, каким же образом можно скрывать реализацию данных.

Рассмотренные в предыдущем  разделе механизмы экспорта и импорта программных сущностей в языке Haskell наводят на мысль о том, что сокрытие реализаций типов можно производить при помощи ограничения экспорта из создаваемого модуля. Действительно, раз ближайшей к интерфейсу программной сущностью по своей сути является класс в языке Haskell, то и оперировать при экс-

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

Это значит, что во всех прикладных функциях невозможно будет использовать ни конструкторов типов, ни их конструкторов данных. В свою очередь это означает, что в сигнатурах функций  нельзя будет указывать конкретный тип, но можно будет только указывать ограничение (Class  a =>). Более того, невозможно будет  пользоваться  механизмом  сопоставления с образцами, поскольку образцы сформировать будет нельзя (нет операций для  конструирования  данных). В этом и заключается высшая степень абстракции данных в языке Haskell.

Этот подход можно сравнить с объектно-ориентированной парадигмой, в которой абстракция данных является одним из главенствующих подходов. Расширяя понятие объектно-ориентированного класса на язык Haskell, можно сказать, что любая функция, у которой  в сигнатуре указан контекст,  ограничивающий  применение функции экземплярами какого-либо класса (в смысле языка Haskell), является методом этого класса, хотя она и не определена внутри класса. При использовании этих функций нет никакой разницы между такими функциями и методами, указанными в определении класса. При этом контекст гарантирует, что для того чтобы создать некий экземпляр класса («реализацию интерфейса» в понимании объектно-ориентированной парадигмы), нужно определить не все методы, а совсем немного (подмножество тех, что перечислены в определении класса). В этом  состоит естественный способ расширения  интерфейсов, который  никак не влияет на уже написанный код, позволяя добавлять к интерфейсу новые методы.

4.2.         Кое-что  ещё о модулях

Наконец, остаётся отметить, что имеются и иные аспекты использования модулей в языке Haskell. Правда, все эти тонкости можно пересчитать по пальцам, поэтому они просто перечислены ниже.

1)                        В  связи с тем, что  такая  программная сущность, как  экземпляр класса в языке  Haskell, не имеет наименования,  она экспортируется модулем и импортируется внешним модулем всегда в случае экспорта или импорта и класса, и типа, для которого определён экземпляр.

2)                        Трансляторы языка Haskell ищут файлы с модулями для включения в текущем каталоге проекта либо в специальных каталогах, в которых собраны модули стандартных библиотек. При коллизии имён модулей приоритет использования имеет тот, который находится в каталоге проекта.

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

import Data.List

Такая  директива импорта означает, что модуль List находится в  файле

/data/list.hs в каталоге модулей.

Источник: Душкин Р. В., Справочник по языку Haskell. М.: ДМК Пресс, 2008. 544 с., ил.

По теме:

  • Комментарии