ТОП 10:

У символа могут быть свойства



В Лиспе с символом можно связать именованные свойства (property). Свойства символа записываются в хранимый вместе с символом список свойств (property list, p-list).

 

У свойств есть имя и значение

Список свойств может быть пуст или содержать произвольное количество свойств. Его форма такова:

 

(имя1 значение1 имя2 значение2 … имяN значениеN)

Например, у символа ЯГОДА-РЯБИНЫ может быть такой список свойств:

 

(вкус кислый цвет красный)

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

 

Системные и определяемые свойства

Ранее мы показали, что с символом связаны лишь его имя - произвольное, назначенное функцией присваивания (SETQ), значение; назначенное определением функции (DEFUN) описание вычислений (лямбда-выражение). Значение и определение функции являются встроенными системными свойствами, которые управляют работой интерпретатора в различных ситуациях. Функции, используемые для чтения и изменения этих свойств (SETQ, SYMBOL-VALUE, DEFUN, FUNCTION-VALUE и другие), мы уже рассматривали ранее. Весь список свойств также является системным свойством. Работающие со свойствами символов прикладные системы могут свободно определять новые свойства.

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

 

Чтение свойства

Выяснить значение свойства, связанного с символом, можно с помощью функции GET:

 

(GET символ свойства)

Если, например, с символом ЯГОДА-РЯБИНЫ связан определенный нами ранее список свойств, то мы получим следующие результаты:

 

_(get ’ягода-рябины ’вкус)

КИСЛЫЙ

_(get ’ягода-рябины ’вес)

NIL

Так как у символа ЯГОДА-РЯБИНЫ нет свойства ВЕС, то GET вернет значение NIL.

 

 

Присваивание свойства

Присваивание нового свойства или изменение значения существующего свойства в основных диалектах языка Лисп осуществляется псевдофункцией PUTPROP (put property) или PUT:

 

(PUTPROP символ свойство значение)

В Коммон Лиспе функции PUTPROP не существует. Свойства символов находятся в связанных с символами ячейках памяти, для присваивания значений которым используется обобщенная функция присваивания SETF. Присваивание свойства в Коммон Лиспе осуществляется через функции SETF и GET следующим образом:

 

(SETF (GET символ свойство) значение)

Здесь вызов GET возвращает в качестве значения ячейку памяти для данного свойства, содержимое которой обновляет вызов SETF. Присваивание будет работать и в том случае, если ранее у символа не было такого свойства. Приведем пример:

 

_(setf (get ’ягода-рябины ’вес) ’(2 g))

(2 G)

_(get ’ягода-рябины ’вес)

(2 G)

Побочным эффектом вызова будет изменение списка свойств символа ЯГОДА-РЯБИНЫ следующим образом:

 

(ВЕС (2 G) ВКУС КИСЛЫЙ ЦВЕТ КРАСНЫЙ)

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

 

Удаление свойства

Удаление свойства и его значения осуществляется псевдофункцией REMPROP:

 

(REMPROP символ свойство)

Приведем пример:

 

_(remprop ’ягода-рябины ’вкус)

ВКУС

_(get ’ягода-рябины ’вкус)

NIL

Псевдофункция REMPROP возвращает в качестве значения имя удаляемого свойства. Если удаляемого свойства нет, то возвращается NIL. Свойство можно удалить, присвоив ему значение NIL. В этом случае имя свойства и значение NIL физически остаются в списке свойств.

Читать из списка свойств, создавать и обновлять в нем свойства можно не только по отдельности, но и целиком. Например, в Коммон Лиспе значением вызова

 

(SYMBOL-PLIST символ)

является весь список свойств:

 

_(symbol-plist ’ягода-рябины)

(ВЕС (2 G) ЦВЕТ КРАСНЫЙ)

Свойства глобальны

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

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

В некоторых системах можно использовать в качестве обобщения так называемые свободные списки свойств (disembodied property list), несвязанные с каким-либо символом.

 

ЛАБОРАТОРНАЯ РАБОТА №9

 

1. Будут ли меняться списки свойств статических и динамических переменных при смене контекста? Если да, то как?

 

2. Предположим, что у имени города есть свойства х и y, которые содержат координаты места нахождения города относительно некоторого начала координат. Напишите функцию (РАССТОЯНИЕ a b), вычисляющую расстояние между городами a и b, если значением функции (SQRT x) является квадратный корень числа х.

 

3. Предположим, что отец и мать некоторого лица, хранятся как значения соответствующих свойств у символа, обозначающего это лицо. Напишите функцию (РОДИТЕЛИ х), которая возвращает в качестве значения родителей, и предикат (СЕСТРЫ-БРАТЬЯ х1 х2), который истинен в случае, если х1 и х2 – сестры или братья, родные или с одним общим родителем.

 

4. Определите функцию REMPROPS, которая удаляет все свойства символа.

 

 

5. Функция GET возвращает в качестве результата NIL в том случае, если у символа нет данного свойства, либо если значением этого свойства является NIL. Следовательно, функцией GET нельзя проверить, есть ли некоторое свойство в вписке свойств. Напишите предикат

 

(HASPROP символ свойство)

 

который проверяет, обладает ли символ данным свойством.

 

 

ВВОД И ВЫВОД

  1. Ввод и вывод входят в диалог
  2. READ читает и возвращает выражение
  3. Программа ввода выделяет формы
  4. Макросы чтения изменяют синтаксис Лиспа
  5. Символы хранятся в списке объектов
  6. Пакеты или пространства имен
  7. PRINT переводит строку, выводит значение и пробел
  8. PRIN1 и PRINC выводят без перевода строки
  9. TERPRI переводит строку
  10. FORMAT выводит в соответствии с образцом
  11. Использование файлов
  12. LOAD загружает определения

Ввод и вывод входят в диалог

До сих пор в определенных нами функциях ввод данных (READ) и вывод (PRINT) осуществлялись в процессе диалога с интерпретатором. Интерпретатор читал вводимое пользователем выражение, вычислял его значение и возвращал его пользователю. Сами формы и функции не содержали ничего, связанного с вводом или выводом.

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

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

 

 

READ читает и возвращает выражение

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

 

_(read)

(вводимое выражение) ; выражение пользователя

(ВВОДИМОЕ ВЫРАЖЕНИЕ) ; значение функции

READ

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

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

Если прочитанное значение необходимо сохранить для дальнейшего использования, то вызов READ должен быть аргументом какой-нибудь формы, например присваивания (SETQ), которая свяжет полученное выражение:

 

_(setq input (read))

(+ 2 3) ; введенное выражение

(+ 2 3) ; значение

_(input)

(+ 2 3)

Форма, вызывающая интерпретатор, и функция READ совместно с другими функциями позволяют читать выражения внешние по отношению к программе. Из них можно строить новые лисповские выражения или целые программы. Построенные структуры можно вычислить, передав их непосредственно интерпретатору:

 

_(eval input)

_(eval (list (read) (read) (read)))

(+ 2 3)







Последнее изменение этой страницы: 2016-09-05; Нарушение авторского права страницы

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 3.235.172.213 (0.009 с.)