Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Pol_Grem_-_ANSI_Common_Lisp_High_tech_-_2012.pdf
Скачиваний:
28
Добавлен:
12.03.2016
Размер:
4.85 Mб
Скачать

42

Глава 2. Добро пожаловать в Лисп

2.14.Функции как объекты

ВЛиспе­ функции ­– это самые­ обычные­ объек­ты,­ такие­ же как симво­­ лы, строки­ или списки­. Давая­ функции­ имя с помо­щью­ function, мы по­ луча­ем­ ассо­ции­ро­ван­ный­ объект­. Как и quote, function – это специ­аль­­ ный опера­тор,­ и поэто­му­ нам не нужно­ брать в кавыч­ки­ его аргу­мент:­

> (function +) #<Compiled-Function + 17BA4E>

Таким­ странным­ обра­зом­ отобра­жа­ют­ся­ функции­ в типич­ной­ реали­за­­ ции Common Lisp.

До сих пор мы имели­ дело­ только­ с таки­ми­ объек­та­ми,­ кото­рые­ при пе­ чати­ отобра­жа­ют­ся­ так же, как мы их ввели­. Это согла­ше­ние­ не рас­ простра­ня­ет­ся­ на функции­. Встроен­ная­ функция­ + обычно­ явля­ет­ся­ куском­ машин­но­го­ кода­. В каждой­ реали­за­ции­ Common Lisp может­ быть свой способ­ отобра­же­ния­ функций­.

Анало­гич­но­ исполь­зо­ва­нию­ кавыч­ки­ вместо­ quote возмож­но­ употреб­­ ление­ #’ как сокра­ще­ния­ для function:

> #’+

#<Compiled-Function + 17BA4E>

Как и любой­ другой­ объект,­ функция­ может­ служить­ аргу­мен­том­. При­ мером­ функции,­ аргу­мен­том­ кото­рой­ явля­ет­ся­ функция,­ явля­ет­ся­ apply­. Она требу­ет­ функцию­ и список­ ее аргу­мен­тов­ и возвра­ща­ет­ резуль­тат­ вызо­ва­ этой функции­ с задан­ны­ми­ аргу­мен­та­ми:­

>(apply #’+ ’(1 2 3))

6

>(+ 1 2 3)

6

Apply прини­ма­ет­ любое­ коли­че­ст­во­ аргу­мен­тов,­ но послед­ний­ из них обяза­тель­но­ должен­ быть списком:­

> (apply #’+ 1 2 ’(3 4 5)) 15

Функция­ funcall дела­ет­ то же самое,­ но не требу­ет,­ чтобы­ аргу­мен­ты­ были­ упако­ва­ны­ в список:­

> (funcall #’+ 1 2 3) 6

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

Чтобы­ бук­валь­но­ сослать­ся­ на число,­ мы исполь­зу­ем­ после­до­ва­тель­ность­ цифр. Чтобы­ таким­ же обра­зом­ сослать­ся­ на функцию,­ мы исполь­зу­ем­

2.14. Функции как объекты

43

лямбда­-выра­же­ние­. Лямбда­-выра­же­ние ­– это список,­ содер­жа­щий­ сим­ вол lambda и следую­щие­ за ним список­ аргу­мен­тов­ и тело­, состоя­щее­ из 0 или более­ выра­же­ний­. Ниже­ при­веде­но­ лямбда­-выра­же­ние,­ пред­ ставляю­щее­ функцию,­ кото­рая­ склады­ва­ет­ два числа­ и возвра­ща­ет­ их сумму:­

(lambda (x y) (+ x y))

Список­ (x y) содер­жит­ пара­мет­ры,­ за ним следу­ет­ тело­ функции­.

Лямбда­-выра­же­ние­ можно­ считать­ именем­ функции­. Как и обычное­ имя функции,­ лямбда­-выра­же­ние­ может­ быть первым­ элемен­том­ вызо­­ ва функции:­

>((lambda (x) (+ x 100)) 1) 101

адобав­ляя­ #’ к этому­ выра­же­нию,­ можно­ полу­чить­ соот­вет­ст­вую­щую­ функцию:­

>(funcall #’(lambda (x) (+ x 100))

1)

101

Поми­мо­ проче­го,­ такая­ запись­ позво­ля­ет­ исполь­зо­вать­ функции,­ не при­ сваивая­ им имена­.

Что такое Лямбда?

Влямбда­-выра­же­нии­ lambda не явля­ет­ся­ опера­то­ром­. Это просто­ символ­.° В ранних­ диалек­тах­ Лиспа­ он имел свою цель: функции­ имели­ внутрен­нее­ представ­ле­ние­ в виде­ списков,­ и единст­вен­ным­ спосо­бом­ отли­чить­ функцию­ от обычно­го­ списка­ была­ провер­ка­ того,­ явля­ет­ся­ ли первый­ его элемент­ симво­лом­ lambda.

ВCommon Lisp вы може­те­ задать­ функцию­ в виде­ списка,­ но они будут­ иметь отлич­ное­ от списка­ внутрен­нее­ представ­ле­ние,­ по­ этому­ lambda больше­ не требу­ет­ся­. Было­ бы вполне­ возмож­но­ за­ писы­вать­ функции,­ напри­мер,­ так:

((x) (+ x 100))

вместо­

(lambda (x) (+ x 100))

но Лисп-програм­ми­сты­ привык­ли­ начи­нать­ функции­ симво­лом­ lambda, и Common Lisp так­же следу­ет­ этой тради­ции­.

44

Глава 2. Добро пожаловать в Лисп

2.15. Типы

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

Несмот­ря­ на то, что объяв­ле­ния­ типов­ вовсе­ не обяза­тель­ны,­ вы може­те­ зада­вать­ их из сооб­ра­же­ний­ произ­во­ди­тель­но­сти­. Объяв­ле­ния­ типов­ обсу­ж­да­ют­ся­ в разделе 13.3.

В Common Lisp встроен­ные­ типы­ обра­зу­ют­ иерар­хию­ подти­пов­ и надти­­ пов. Объект­ всегда­ имеет­ несколь­ко­ типов­. Напри­мер,­ число­ 27 соот­вет­­ ству­ет­ типам­ fixnum, integer, rational, real, number, atom и t в поряд­ке­ уве­ личе­ния­ общно­сти­. (Числен­­ные типы­ обсу­ж­да­ют­ся­ в главе­ 9.) Тип t яв­ ляет­ся­ самым­ верхним­ во всей иерар­хии,­ поэто­му­ каждый­ объект­ име­ ет тип t.

Функция­ typep опре­де­ля­ет,­ принад­ле­жит­ ли ее первый­ аргу­мент­ к ти­ пу, кото­рый­ зада­ет­ся­ вторым­ аргу­мен­том:­

> (typep 27 ’integer) T

По мере­ изуче­ния­ Common Lisp мы позна­ко­мим­ся­ с самы­ми­ разны­ми­ встроен­ны­ми­ типа­ми­.

2.16.Заглядывая вперед

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

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

Ричард­ Гэбри­эл­ одна­ж­ды­ в полу­шу­точ­ной­ форме­ назвал­ С язы­ком для напи­са­ния­ UNIX.° Также­ и мы можем­ назвать­ Лисп язы­ком для напи­­ сания­ Лиспа­. Но между­ этими­ утвер­жде­ния­ми­ есть суще­ст­вен­­ная раз­ ница­. Язык, кото­рый­ легко­ напи­сать­ на самом­ себе,­ карди­наль­но­ отли­­

Итоги главы

45

чает­ся­ от язы­ка, годно­го­ для напи­са­ния­ каких­-то отдель­ных­ классов­ программ­. Он откры­ва­ет­ новый­ способ­ програм­ми­ро­ва­ния:­ вы може­те­ как писать­ програм­мы­ на таком­ язы­ке, так и совер­шен­ст­во­вать­ язык в соот­вет­ст­вии­ с требо­ва­ния­ми­ своих­ программ­. Если­ вы хоти­те­ понять­ суть програм­ми­ро­ва­ния­ на Лиспе,­ начни­те­ с этой идеи.

Итоги главы

1.Лисп инте­рак­ти­вен­. Вводя­ выра­же­ние­ в toplevel, вы тут же полу­чае­­ те его значе­ние­.

2.Програм­мы­ на Лиспе­ состо­ят­ из выра­же­ний­. Выра­же­ние­ может­ быть атомом­ или списком,­ состоя­щим­ из опера­то­ра­ и следую­щих­ за ним аргу­мен­тов­. Благо­да­ря­ префикс­ной­ запи­си­ этих аргу­мен­тов­ может­ быть сколько­ угодно­.

3.Поря­док­ вычис­ле­ния­ вызо­вов­ функций­ в Common Lisp таков:­ снача­­ ла вычис­ля­ют­ся­ аргу­мен­ты­ слева­ напра­во,­ затем­ они пере­да­ют­ся­ опера­то­ру­. Опера­тор­ quote не подчи­ня­ет­ся­ этому­ поряд­ку­ и возвра­­ щает­ само­ выра­же­ние­ неиз­мен­ным­ (вместо­ его значе­ния)­ .

4.Поми­мо­ привыч­ных­ типов­ данных­ в Лиспе­ есть симво­лы­ и списки­. Програм­мы­ на Лиспе­ запи­сы­ва­ют­ся­ в виде­ списков,­ поэто­му­ легко­ состав­лять­ програм­мы,­ кото­рые­ пишут­ другие­ програм­мы­.

5.Есть три основ­ные­ функции­ для обра­ще­ния­ со списка­ми:­ cons, строя­ щая список;­ car, возвра­щаю­щая­ первый­ элемент­ списка;­ cdr, возвра­­ щающая­ весь список,­ за исклю­че­ни­ем­ его перво­го­ элемен­та­.

6.В Common Lisp символ­ t имеет­ истин­ное­ значе­ние,­ nil – ложное­. В контек­сте­ логи­че­ских­ опера­ций­ все, кроме­ nil, явля­ет­ся­ истин­­ ным. Основ­ной­ услов­ный­ опера­тор ­– if. Опера­то­ры­ and и or также­ мо­ гут считать­ся­ услов­ны­ми­.

7.Лисп состо­ит­ по большей­ части­ из функций­. Собст­вен­­ные функции­ можно­ созда­вать­ с помо­щью­ defun.

8.Функция,­ кото­рая­ вызы­­вает­ сама­ себя,­ назы­­вает­ся­ рекур­сив­ной­. Рекур­сив­ную­ функцию­ следу­ет­ пони­мать­ как процесс,­ но не как аг­ регат­.

9.Скобки­ не созда­ют­ затруд­не­ний,­ посколь­ку­ програм­ми­сты­ пишут­ и чита­ют­ Лисп-код по отсту­пам­.

10.Основ­ные­ функции­ ввода­-выво­да:­ read, являю­щая­ся­ полно­цен­ным­ обра­бот­чи­ком­ Лисп-выра­же­ний,­ и format, исполь­зую­щая­ для выво­да­ задан­ный­ шаблон­.

11.Локаль­ные­ пере­мен­ные­ созда­ют­ся­ с помо­щью­ let, глобаль­ные ­– с по­ мощью­ defparameter.

12.Для присваи­ва­ния­ исполь­зу­ет­ся­ опера­тор­ setf. Его первый­ аргу­мент­ может­ быть как пере­мен­ной,­ так и выра­же­ни­ем­.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]