Понятия

Явное и неявное определение

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

Абстракция данных

  Первоначально основой для выделения различных типов данных служил, внутренний формат представления данных в памяти машины. Поскольку данные различных типов обрабатывались разными командами, то оказалось полезным объединить формальное описание типа с описанием применяемых действий. Получаемая от этого выгода становится тем более очевидной, чем больше используется новых различных типов. В связи с проектированием языка Алгол-68 стало ясным, сколь важным было точное определение как типов данных, так и действий над ними. Это положило начало развитию специальной области исследований, названной теорией абстрактных типов данных.
  Под абстракцией данных понимают отделение свойств данных от самих объектов данных. Под абстрактным типом данных понимается тип данных, который определён через применимые к данному типу операции независимо от того, как представлены значения объектов данного типа.
  Например, списки образуют абстрактный тип данных. Его объекты можно реализовать с помощью списочных ячеек и указателей или какой-нибудь другой структуры или типа данных. Базовые функции образуют множество операций (методы типа). Их можно применять к спискам независимо от того, как последние реализованы на более низком уровне абстракции.
  Пользуясь абстракцией типов данных, программист может забыть о технической реализации (значений объектов) типа, которая с точки зрения представления данных из проблемной области несущественна, и сосредоточиться на решении самой проблемы. В то же время вычисления в системе естественным образом распределяется между различными типами данных.
  Абстрактные типы данных предлагают естественный способ разбиения программы на модули, спецификации и верификации модулей. С помощью абстракции данных можно упрощать программирование, уменьшая количество ошибок, и создавать более читаемые и легко модифицируемые программы, в которых можно менять структуры данных, не внося больших изменений в программы.
  Абстракция данных позволяет определить универсальные действия, выглядящие с точки зрения пользователя одинаково, но реализующиеся специфическим образом в зависимости от типов объектов. Это упрощает программирование и сопровождение программ. Изменяя программу, не нужно делать изменения во всех местах, где используется данный тип. Достаточно внести изменения в определение типа. Это обстоятельство особенно важно в том случае, когда программы велики по размерам или когда над ними работают несколько программистов.
  В рамках исследований по искусственному интеллекту в течение нескольких десятилетий были предложены и отработаны многочисленные структуры данных и формы их представления. Некоторые из них уже с самого начала входили в состав Лиспа (например, так называемые ассоциативные списки и списки свойств). Некоторые более новые разработки вошли в Лисп-системы позже (например, объекты). Кроме них в Лисп-системы были включены типы данных, использованные в других языках программирования, - это различные виды чисел, строки, векторы и т.д.
  Благодаря естественной расширяемости и открытости Лиспа в языке было просто определять новые типы данных и средства абстракции данных. Ни в одном другом языке программирования не найдётся столь широкого и многостороннего выбора готовых типов данных и средств для определения новых типов, как в Лиспе. Однако списки и работа с ними образуют базовый механизм, посредством которого можно использовать и объединить в единое целое лисповские объекты различных типов и с помощью которого можно реализовать новые способы представления данных.

Классы и методы

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

В Лиспе тип связан со значением, а не с именем

  В объекте данных можно различить его имя, сам объект, или значение, и тип объекта. Именем объекта является символ, который используется как переменная или как представитель объекта. Тип объекта определяет его общие свойства.
  В Лиспе тип объекта данных связан не с его именем, а с самим объектом. Именно этим Лисп отличается от многих других языков программирования. Например, в Паскале именам переменных присваивается определённый тип, и переменные нельзя использовать для представления объектов другого типа. В Фортране в свою очередь за частью имён переменных тип закреплён уже в определении языка с 1950-х годов (имена, начинающиеся на буквы i, j и k). Закрепление типа обычно осуществляется при написании программы в момент описания переменной, и его нельзя изменить в ходе работы программы.
  В Лиспе в качестве значения символу можно присвоить объект произвольного типа (число, символ, список, строку, вектор, поток, объект, функцию, макрос и т.д.), не заботясь о типе переменной. Одна и та же переменная может в различные моменты времени и в различной обстановке представлять лисповские объекты различных типов. Соответствие значения реальной ситуации, например аргумента функции, проверяется лишь в ходе конкретного вычисления.
  Исходя из того, что переменные не имеют типов, Лисп называют безтиповым языком. Подобный термин не означает того, что в языке вообще нет типов данных. Динамичность типов совместно с абстракцией данных и универсальным определением действий позволяет записывать программы в более простой и более короткой форме, чем в традиционных языках.

Проверка и преобразование типов

  Для объектов, имеющих различные типы, нужны свои функции на базовом уровне. Кроме этого, для каждого типа нужен предикат, проверяющий принадлежность к этому типу. Например, (nil atom x) проверяет, является ли x атомом. Наряду с предикатами, различающими типы (atom, consp, listp, numberp, stringp, vectorp и другие), тип объекта можно определить и с помощью функции class-of, которая возвращает в качестве значения определение класса аргумента:

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

>("Abc" list) ; из строки в список букв
(#\A #\b #\c)
>(1/3 string)
; из числа в строку
"1/3"

Иерархия типов

  Типы данных образуют иерархию понятий: расположенные ниже классы типов автоматически входят и в расположенный выше более абстрактный класс данного типа. Наиболее общим типом является тип nil.

  Встроенные функции, определённые для типа, расположенного выше по иерархии, можно применять и для объектов, типы которых принадлежат более низким уровням.

>(nil if true 1 2)
1
>("test" if true 1 2)
1

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

>(nil string)
"nil"
>(true string)
"true"
>(1 string)
"1"

Определение новых типов

  Наряду с уже существующими типами программист может сам определить формой defclass новые ориентированные на задачу классы объектов. Для классов можно далее определить иерархию, для полей задать значения по умолчанию, используя конструктор.
  Разграничение между системными и используемыми в решении конкретной задачи типами часто столь же сложно, как между системными и пользовательскими функциями.
  Концепция объектов оказывается особенно полезным и разносторонним средством для реализации новых, особенно "активных" типов. Объектное мышление просматривается в том числе и в иерархии типов.