Скачать презентацию Лисповская память состоит из списочных ячеек Оперативная память Скачать презентацию Лисповская память состоит из списочных ячеек Оперативная память

Лисп. Лекция 7.pptx

  • Количество слайдов: 44

Лисповская память состоит из списочных ячеек Оперативная память машины, на которой работает Лисп-система, логически Лисповская память состоит из списочных ячеек Оперативная память машины, на которой работает Лисп-система, логически разбивается на маленькие области, которые называются списочными ячейками. Списочная ячейка состоит из двух частей, полей CAR и CDR. Каждое из полей содержит указатель. Указатель может ссылаться на другую списочную ячейку или на некоторый другой лисповский объект, как, например, атом.

Графически списочная ячейка представляется прямоугольником (рис. ), разделенным на части (поля) CAR и CDR. Графически списочная ячейка представляется прямоугольником (рис. ), разделенным на части (поля) CAR и CDR. Указатель изображается в виде стрелки, начинающейся в одной из частей прямоугольника и заканчивающейся на изображении другой ячейки или атоме, на которые ссылается указатель.

Значение представляется указателем Указателем списка является указатель на первую ячейку списка. На ячейку могут Значение представляется указателем Указателем списка является указатель на первую ячейку списка. На ячейку могут указывать не только поля CAR и CDR других ячеек, но и используемый в качестве переменной символ, указатель из которого ссылается на объект, являющийся значением символа. Указатель на значение хранится вместе с символом в качестве его системного свойства.

Побочным эффектом функции присваивания SETQ является замещение указателя в поле значения символа. Например, следующий Побочным эффектом функции присваивания SETQ является замещение указателя в поле значения символа. Например, следующий вызов: _(setq список '(а Ь с)) (А В С) создает в качестве побочного эффекта изображенную на рис. штриховую стрелку.

Графически ссылку на пустой список изображают в виде перечеркнутого поля. Указатели из полей CAR Графически ссылку на пустой список изображают в виде перечеркнутого поля. Указатели из полей CAR ячеек списка ссылаются на структуры, являющиеся элементами списка, в данном случае на атомы А, В и С.

CONS создает ячейку и возвращает указатель на нее Допустим, что у нас есть два CONS создает ячейку и возвращает указатель на нее Допустим, что у нас есть два списка: >(setq голова '(Ь с)) (В С) >(setq хвост '(a b с)) (А В С) Вызов функции >(cons голова хвост) ((В С) А В С) строит новый список из ранее построенных списков ГОЛОВА и ХВОСТ так, как это показано на рис.

Заметим, что применение функции CONS не изменило структуры списков, являющихся аргументами, и не изменило Заметим, что применение функции CONS не изменило структуры списков, являющихся аргументами, и не изменило значений переменных ГОЛОВА и ХВОСТ.

У списков могут быть общие части На одну ячейку может указывать одна или более У списков могут быть общие части На одну ячейку может указывать одна или более стрелок из списочных ячеек, однако из каждого поля ячейки может исходить лишь одна стрелка. Если на некоторую ячейку есть несколько указателей, то эта ячейка будет описывать общее подвыражение. Например, в списке (кто-то приходит кто-то уходит) символ КТО-ТО является общим подвыражением, на которое ссылаются указатели из поля CAR из первой и из третьей ячейки списка.

Если элементами списка являются не атомы, а подсписки, то на месте атомов будут находится Если элементами списка являются не атомы, а подсписки, то на месте атомов будут находится первые ячейки подсписков. Например, построенная вызовом _(setq список 1 '((Ь с) a b с) ((В С) А В С) структура изображена на рис.

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

> (car список 1) (B С) > (cddr список 1) (B С) являются логически > (car список 1) (B С) > (cddr список 1) (B С) являются логически одинаковым списком (В С), хотя они и представлены различными cписочными ячейками: > (equal (car список 1) (cddr список 1)) Т

Однако список (В С), как видно из следующего рис. , может состоять и из Однако список (В С), как видно из следующего рис. , может состоять и из тех же ячеек.

Эту структуру можно создать с помощью следующей последовательности вызовов: > (setq bс ‘(b c)) Эту структуру можно создать с помощью следующей последовательности вызовов: > (setq bс ‘(b c)) (В С) > (setq abc (cons 'a bc)) (ABC) > (setq список 2 (cons bc abc)) ((В С)А В C) >Список 2 ((В С)А В C)

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

Логическое и физическое равенство Логически сравнивая списки, мы использовали предикат EQUAL, сравнивающий не физические Логическое и физическое равенство Логически сравнивая списки, мы использовали предикат EQUAL, сравнивающий не физические указатели, а совпадение структурного построения списков и совпадение атомов, формирующих список. Предикат EQ можно использовать лишь для сравнения двух символов. Во многих реализациях языка Лисп предикат EQ обобщен таким образом, что с его помощью можно определить физическое равенство двух выражений не зависимо от того, является ли он атомом или списком. > (equal (car список 2) (cddr список 2)) T > (eq (car список 2) (cddr список 2)) T

Точечная пара соответствует списочной ячейке Определяя базовую функцию CONS, мы предполагали, что ее вторым Точечная пара соответствует списочной ячейке Определяя базовую функцию CONS, мы предполагали, что ее вторым аргументом является список. Это ограничение не является необходимым, так как при помощи списочной ячейки можно было бы, например, результат вызова (cons 'а 'Ь) представить в виде структуры, изображенной на рис.

На рис. показан не список, а более общее символьное выражение, так называемая точечная пара. На рис. показан не список, а более общее символьное выражение, так называемая точечная пара. Для сравнения на следующем рис. мы изобразили список (А В).

Название точечной пары происходит из использованной в ее записи точечной нотации, в которой для Название точечной пары происходит из использованной в ее записи точечной нотации, в которой для разделения полей CAR и CDR используется выделенная пробелами точка: _(cons 'а 'b) (А. В) Выражение слева от точки (атом, список или другая точечная пара) соответствует значению поля CAR списочной ячейки, а выражение справа от точки - значению поля CDR. Базовые функции CAR и CDR действуют совершенно симметрично:

_(саr '(а. b)) ; обратите внимание на А ; пробелы, выделяющие точку _(cdr '(а. _(саr '(а. b)) ; обратите внимание на А ; пробелы, выделяющие точку _(cdr '(а. (b. с))) (В. С) Точечная нотация позволяет расширить класс объектов, изображаемых с помощью списков.

Варианты точечной и списочной записей Любой список можно записать в точечной нотации. Преобразование можно Варианты точечной и списочной записей Любой список можно записать в точечной нотации. Преобразование можно осуществить (на всех уровнях списка) следующим образом: (al a 2. . . a. N) (al. (a 2. . (a. N. NIL). . . ))

Использование точечных пар в программировании на Лиспе в общем-то излишне. Точечные пары применяются в Использование точечных пар в программировании на Лиспе в общем-то излишне. Точечные пары применяются в теории. Часто с их помощью обозначают список заранее неизвестной длины в виде (голова. хвост) Точечные пары используются совместно с некоторыми типами данных и с ассоциативными списками.

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

RPLACA и RPLACD изменяют содержимое полей Основными функциями, изменяющими физическую структуру списков, являются RPLACA RPLACA и RPLACD изменяют содержимое полей Основными функциями, изменяющими физическую структуру списков, являются RPLACA (replace CAR) и RPLACD (replace CDR) которые уничтожают прежние и записывают новые значения в поля CAR и CDR списочной ячейки: (RPLACA ячейка значение-поля) (RPLACD ячейка значение-поля)

Обе функции возвращают в качестве результата указатель на измененную списочную ячейку. >(setq поезд ‘(паровоз Обе функции возвращают в качестве результата указатель на измененную списочную ячейку. >(setq поезд ‘(паровоз 1 А В C)) (ПАР 0 ВОЗ 1 A B C) >(rplaca поезд 'паровоз 2) (ПАР 0 В 032 А В С) >поезд (ПАР 0 В 032 A B C) >(грlаса (cdr поезд) 'тендер) (ТЕНДЕР В С) поезд (ПАР 0 В 032 ТЕНДЕР В С)

Функция RPLACD выполняется так же, как RPLACA, с той разницей, что меняется значение поля Функция RPLACD выполняется так же, как RPLACA, с той разницей, что меняется значение поля CDR: >(rplacd поезд '(к l m)) (ПАР 0 В 032 К L M) >поезд (ПАР 0 В 032 К L М)

Изменение структуры может ускорить вычисления Разумно использованные структуроразрушающие функции могут быть эффективными и полезными Изменение структуры может ускорить вычисления Разумно использованные структуроразрушающие функции могут быть эффективными и полезными инструментами. Рассмотрим, как можно с помощью структуроразрушающих функций повысить эффективность функции APPEND для списков. Эта функция объединяет в один список списки, являющиеся его аргументами: (SETQ begin '(a b)) => (a b) (SETQ end '(c d)) => (c d) (SETQ result (APPEND begin end)) => (a b c d)

NCONC APPEND NCONC APPEND

CL-USER 4 > (SETQ result 2 (NCONC begin end)) (A B C D) CL-USER CL-USER 4 > (SETQ result 2 (NCONC begin end)) (A B C D) CL-USER 5 > eq result 2 NIL CL-USER 6 > equal result 2 T CL-USER 7 > begin (A B C D) CL-USER 8 > end (C D)

Типы данных ATOM CONSP LISTP NUMBERP STRINGP ARRAYP Обобщенный предикат проверки типа: (TYPEP объект Типы данных ATOM CONSP LISTP NUMBERP STRINGP ARRAYP Обобщенный предикат проверки типа: (TYPEP объект тип) => T или NIL Пример: (TYPEP 'spisok 'atom) => T Функция, возвращающая тип аргумента: (TYPE-OF объект) => тип (TYPE-OF 'spisok) => SYMBOL (TYPE-OF "spisok") => STRING

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

Векторы. Массивы • Векторы Common Lisp являются базовой коллекцией с доступом по целочисленному индексу, Векторы. Массивы • Векторы Common Lisp являются базовой коллекцией с доступом по целочисленному индексу, и имеют две разновидности. Векторы с фиксированным размером похожи на массивы в языках, подобных Java: простая надстройка над областью памяти, которая хранит элементы вектора. С другой стороны, векторы с изменяемым размером, более похожи на векторы в Perl или Ruby, списки в Python, или на класс Array. List в Java: они прячут детали реализации хранилища данных, позволяя векторам менять размер по мере добавления или удаления элементов

Вектор, массив с фиксированным размером >(vector) ==> #() >(vector 1) ==> #(1) >(vector 1 Вектор, массив с фиксированным размером >(vector) ==> #() >(vector 1) ==> #(1) >(vector 1 2) ==> #(1 2) Массивы создаются формой: (MAKE-ARRAY (N 1 N 2 … NM) режимы) Функция возвращает в качестве значения новый объект – массив. NJ – размер по J-й размерности; размерность 0 – один элемент; 1 – вектор, 2 – матрица и т. д. >(make-array 5 : initial-element nil) #(NIL NIL NIL)

>(SETQ mass (MAKE-ARRAY 10 : INITIAL-ELEMENT 'c)) => #(C C C) >setq b (make-array >(SETQ mass (MAKE-ARRAY 10 : INITIAL-ELEMENT 'c)) => #(C C C) >setq b (make-array '(2 3 ) : initial-element '3) => #2 A((3 3 3)) >setf (aref b 1 2) 'c) => C >b => #2 A((3 3 3) (3 3 C)) - индексация элементов массива с начинается с 0. Ссылка на элемент массива осуществляется с помощью функции: (AREF массив n 1 n 2 … n. M)

Вектор, массив с изменяемым размером вектор (массив) с изменяемым размером отслеживает число элементов, сохраненных Вектор, массив с изменяемым размером вектор (массив) с изменяемым размером отслеживает число элементов, сохраненных в векторе. Это число хранится в указателе заполнения вектора (vector's fill pointer) это индекс следующей позиции, которая будет заполнена. (make-array 5 : fill-pointer 0) ==> #() Создаст массив с размером до 5 элементов

(defparameter *x* (make-array 5 : fill-pointer 0)) (vector-push 'a *x*) ==> 0 *x* ==> (defparameter *x* (make-array 5 : fill-pointer 0)) (vector-push 'a *x*) ==> 0 *x* ==> #(A) (vector-push 'b *x*) ==> 1 *x* ==> #(A B) (vector-push 'c *x*) ==> 2 *x* ==> #(A B C) (vector-pop *x*) ==> C *x* ==> #(A B) (vector-pop *x*) ==> B *x* ==> #(A) (vector-pop *x*) ==> A *x* ==> #()

(make-array 5 : fill-pointer 0 : adjustable t) ==> #() Создаст вектор, размер которого (make-array 5 : fill-pointer 0 : adjustable t) ==> #() Создаст вектор, размер которого может изменяться по мере необходимости. Чтобы добавить элементы в такой вектор, необходимо использовать функцию VECTOR-PUSH-EXTEND Все векторы, с которыми мы уже встречались, были векторами общего назначения, которые могут хранить объекты любого типа. Векторы с определенным типом параметров задаются ключевым параметром : element-type (make-array 5 : fill-pointer 0 : adjustable t : element-type 'character) ==> "" ; вектор-строка

Функции для работы с элементами последовательностей >(defparameter *x* (vector 1 2 3)) > (length Функции для работы с элементами последовательностей >(defparameter *x* (vector 1 2 3)) > (length *x*) ==> 3 >elt *x* 0) ==> 1 >(elt *x* 1) ==> 2 >(elt *x* 2) ==> 3 >(elt *x* 3) ==> error ELT возвращает ячейку, для которой можно выполнить SETF, так что вы можете установить значение отдельного элемента с помощью вот такого кода: >(setf (elt *x* 0) 10)==>10 *x* ==> #(10 2 3)

Функции для работы с элементами последовательностей Функции для работы с элементами последовательностей

Примеры использования >(count 1 #(1 2 3 4)) ==> 3 >(remove 1 #(1 2 Примеры использования >(count 1 #(1 2 3 4)) ==> 3 >(remove 1 #(1 2 3 4)) ==> #(2 2 3 4) >(remove 1 '(1 2 3 4)) ==> (2 2 3 4) >(remove #a "foobarbaz") ==> "foobrbz" >(substitute 10 1 #(1 2 3 4)) ==> #(10 2 3 4) >(substitute 10 1 '(1 2 3 4)) ==> (10 2 3 4) >(substitute #x #b "foobarbaz") ==> "fooxarxaz" >(find 1 #(1 2 3 4)) ==> 1 ; объект или NIL >(find 10 #(1 2 3 4)) ==> NIL >(position 1 #(1 2 3 4)) ==> 0

Стандартные именованные аргументы функций работы с последовательностями Аргумент Описание Значение по умолчанию : test Стандартные именованные аргументы функций работы с последовательностями Аргумент Описание Значение по умолчанию : test Функция двух аргументов, используемая для сравнения EQL элементов (или значений, извлеченных функцией : key) с указанным объектом. : key Функция одного аргумента, используемая для NIL извлечения значения из элемента последовательности. NIL указывает на использование самого элемента. Начальный индекс (включительно) обрабатываемой последовательности. 0 Конечный индекс (n-1) обрабатываемой последовательности. NIL указывает на конец последовательности. NIL : from-end Если имеет истинное значение, то последовательность будет обрабатываться в обратном порядке, от конца к началу. NIL : count Число, указывающее количество удаляемых или заменяемых элементов, или NIL для всех элементов (только для REMOVE и SUBSTITUTE). NIL : start : end

1 >(find 'a" src="https://present5.com/presentation/87196883_441528984/image-41.jpg" alt="Примеры использования >(count "foo" #("foo" "bar" "baz") : test #'string=) ==> 1 >(find 'a" /> Примеры использования >(count "foo" #("foo" "bar" "baz") : test #'string=) ==> 1 >(find 'a #((a 10) (b 20) (a 30) (b 40)) : key #'first) ==> (A 10) >(find 'a #((a 10) (b 20) (a 30) (b 40)) : key #'first : fromend t) ==> (A 30) >(remove #a "foobarbaz" : count 1) ==> "foobrbaz" >(remove #a "foobarbaz" : count 1 : from-end t) ==> "foobarbz"

Аналогичные функции высшего порядка >(count-if #'evenp #(1 2 3 4 5)) ==> 2 >(count-if-not Аналогичные функции высшего порядка >(count-if #'evenp #(1 2 3 4 5)) ==> 2 >(count-if-not #'evenp #(1 2 3 4 5)) ==> 3 >(position-if #'digit-char-p "abcd 0001") ==> 4 >(remove-if-not #'(lambda (x) (char= (elt x 0) #f)) #("foo" "bar" "baz" "foom")) ==> #("foo" "foom") >(count-if #'evenp #((1 a) (2 b) (3 c) (4 d) (5 e)) : key #'first) ==> 2 >(count-if-not #'evenp #((1 a) (2 b) (3 c) (4 d) (5 e)) : key #'first) ==> 3 >(remove-if-not #'alpha-char-p #("foo" "bar" "1 baz") : key #'(lambda (x) (elt x 0))) ==> #("foo" "bar“)

Хэш-массивы • Кроме массивов с численными индексами можно работать с хэш-массивами. Если с помощью Хэш-массивы • Кроме массивов с численными индексами можно работать с хэш-массивами. Если с помощью массива можно связать Лисповские объекты с числовыми значениями индексов, то хэш-массив связывает два произвольных Лисповских объекта (атомы, списки, массивы, хэш-массивы и т. д. ) • При работе с хэш-массивами в качестве индекса элемента массива используется указатель на Лисповский объект. • Хэш-массивы используют для организации баз данных с целью увеличения быстроты поиска информации. При этом по значению ключа поиска вычисляется хэшфункция, которая вырабатывает адрес искомого элемента в памяти.