1. Функциональное программирование. Основы Лиспа

Вид материалаДокументы

Содержание


2. Списки в Лиспе Списки. Функции для работы со списками
CAR обеспечивает доступ к первому элементу списка — его "голове".
EQ выполняет проверку атомарных
Многократные CAR-CDR
Подобный материал:
1   2   3   4   5   6   7
^

2. Списки в Лиспе

Списки. Функции для работы со списками


Список – это основной тип данных в Lisp.

Списки - последовательности S-выражений, построенные из атомов, заключенных в скобки и разделенных пробелами, например:

((имя Джон Смит) (возраст 99) (женат #Т) (дети (Том Мэри)))

Особым S-выражением является пустой список (), который считается атомом. Для обозначения пустого списка используется также специальная константа nil.

Примеры списков:

;пятиэлементный список

(1 2 3 4 5)

;четырехэлементный список

(1 2 ((3) 4) 5)

;одноэлементный список

((1 2 3 4 5))

Первый элемент списка называется головой списка, все прочие элементы, кроме первого, представленные как список, называются хвостом списка.

Примеры разделения списка на голову и хвост:

Список

Голова

Хвост

(1 2 3 4 5)

1

(2 3 4 5)

(1 2 ((3) 4) 5)

1

(2 ((3) 4) 5)

((1 2 3 4 5))

(1 2 3 4 5)

()

(1)

1

()



Списки легко реализовать с помощью структуры из двух указателей (для примера выше):



Для обработки S-выражений достаточно пяти функций:

Функция ^ CAR обеспечивает доступ к первому элементу списка — его "голове".

`X

(CAR X)

(A B C)

A

(A)

A

((A B)(C D))

(A B)

Функция CDR — возвращает укороченный на один элемент список (отбрасывая его первый элемент, «голову») — его «хвост», т.е. что, что остается после удаления головы.

`X

(CDR X)

(A B C)

(B C)

(A)

()

((A B)(C D))

((C D))



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

(*) Чтобы отличать константные S-выражения от вычисляемых выражений, перед константой будем ставить апостроф (например, `х - символьная константа, а х – переменная). При сцеплении двух атомов cons(`A,`B) получается S-выражение, которое не является списком. Будем его записывать как точечную пару (А . B). Результат cons(`А,0) можно также записать либо как список (А) либо как точечную пару (А . ()). S-выражение (А . (B . (С . D))) можно записывать в более простой форме (A B C. D).

`X

`Y

(CONS X Y)

A

(B C)

(A B C)

A

()

(A)

(A B)

((C D))

((A B) (C D))

(A B)

(C D)

((A B) C D)

A

B

(A . B)

Функция ATOM позволяет различать составные и атомарные объекты: на атомах ее значение "истина", а на структурированных объектах — "ложь".

`X

(ATOM X)

A

T

(A)

NIL

()

T

123

T

NIL

T



Функция ^ EQ выполняет проверку атомарных объектов на равенство. Если оба аргумента функция являются списками, то результат не определен, так как анализируется только значение указателя.

`X

`Y

(EQ X Y)

A

A

T

(A)

(A)

NIL

A

(A)

NIL

Для многошагового доступа к отдельным элементам списка удобно пользоваться мнемоничными обозначениями композиций из многократных CAR-CDR. Имена таких композиций устроены как цепочки из "a" или "d", задающие маршрут движения из шагов CAR и CDR, соответственно, расположенный между "c" и "r". Указанные таким способом CAR-CDR исполняются с ближайшего к аргументу шага, т.е. в порядке, обратном записи.

Примеры многошагового доступа к элементам структуры

 

^ Многократные CAR-CDR

Вычисляются в порядке, обратном записи:

CAAR

((A) B C)

A

CADR

(A B C)

B — CDR затем CAR

CADDR

(A B C)

C — (дважды CDR) затем CAR

CADADR

(A (B C) D)

C — два раза (CDR затем CAR)

(*) Имена функций car и car происходят от имен регистров компьютера, на котором был реализован первый компилятор языка LISP. Эти имена сохранились, так как позволяют использовать вместо car{cdr(cdr(x))) сокращенную запись caddr(x) (третий элемент списка х), см. примеры далее.

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

Различие истинностных значений в Лиспе принято отождествлять с разницей между пустым списком и остальными объектами, которым программист может придать в программе некоторый другой смысл. Таким образом, значение "ложь" — это всегда Nil. (Во многих языках программирования используется 0 – 1 или идентификаторы True — False и др.)

Если требуется явно изобразить истинностное значение, то для определенности в качестве значения "истина" используется константа — атом  T (true) как стандартное представление, но роль такого значения может выполнить любой, отличный от пустого списка, объект.