ТОП 10:

Другие условные предложения: IF, WHEN, UNLESS и CASE



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

В простом случае можно воспользоваться вполне естественной и содержащей мало скобок формой IF.

 

(IF условие то-форма иначе-форма)

ó

(COND (условие то-форма)

иначе-форма))

_(if (atom t) ’атом ’список)

ATOM

Можно еще использовать формы WHEN и UNLESS:

 

(WHEN условие форма1 форма2 . . .)

ó

(UNLESS (NOT условие) форма1 форма2 . . .)

ó

(COND (условие форма1 форма2 . . .))

ó

(IF условие (PROGN форма1 форма2 . . .) NIL)

Также можно применять подобное используемому в языке Паскаль выбирающее предложение CASE:

 

(CASE ключ

(список-ключей1 m11 m12 . . .)

(список-ключей2 m21 m22 . . .)

. . . )

Сначала в форме CASE вычисляется значение ключевой формы ключ. Затем его сравнивают с элементами списков ключей список-ключейi, с которого начинаются альтернативы. Когда в списке найдено значение ключевой формы, начинают вычисляться соответствующие формы mi1, mi2, . . ., значение последней из которых и возвращается в качестве значения всего предложения CASE (неявный PROGN).

 

 

Циклические вычисления: предложение DO

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

Самым общим циклическим или итерационным предложением в Коммон Лиспе является DO. С его помощью можно задать:

1. Набор внутренних статических переменных с их начальными значениями, как в предложении LET(*).

2. Ряд форм, вычисляемых последовательно в цикле.

3. Изменения внутренних переменных после каждой итерации (например, наращивание счетчиков и т.п.).

4. Условие окончания цикла и выражение, значение которого будет значением всего предложения.

 

Предложение DO имеет следующую форму:

 

(DO ((var1 знач1 шаг1) (var2 знач2 шаг2) . . . )

(условие-окончания форма11 форма12 . . .)

форма21

Форма22

. . .)

Первый аргумент предложения описывает внутренние переменные var1, var2, . . ., их начальные значения знач1, знач2, . . . , а также формы обновления шаг1, шаг2, . . . Вычисление предложения DO начинается с присваивания значений переменным формы таким же образом, как в случае предложения LET. Переменным, начальное значение которых не задано, присваивается по умолчанию NIL. В каждом цикле после присваивания значения переменным вычисляется условие окончания. Как только значение условия не равно NIL, т.е. условие окончания истинно, последовательно вычисляются формы форма1i, и значение последней формы возвращается как значение всего предложения DO. В противном случае последовательно вычисляются формы форма2i из тела предложения DO. На следующем цикле переменным vari присваиваются (одновременно) значения форм шагi, вычисляемых в текущем контексте, проверяется условие окончания и т.д. Если для переменной не задана форма, по которой она обновляется, то значение переменной не меняется.

Для примера с помощью предложения DO определим функцию, вычисляющую n-ю степень числа (n – целое, положительное):

 

_(defun expt1 (x n)

(do ((результат 1)) ; начальное значение

((= n 0) результат) ; условие окончания

(setq результат (* результат х))

(setq n (- n 1))))

EXPT1

_(expt1 2 3)

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

Идея определения состоит в том, чтобы умножить Х на себя N раз, что и является N-й степенью числа Х. В каждом цикле значение переменной РЕЗУЛЬТАТ умножается на Х до тех пор, пока значение счетчика N не уменьшится до 0 и конечное значение переменной РЕЗУЛЬТАТ можно будет выдать в качестве значения предложения DO.

Так как в предложении DO можно совместно с переменными описать и закон их изменения, то функцию EXPT можно было бы задать и такой формой:

 

_(defun expt2 (x n)

(do ((результат х (* результат х))

(разы n (- разы 1)))

((= разы 1) результат))) ; условие окончания

В этом определении нет вычисляемого в цикле тела предложения DO, присутствуют только описания переменных, законов их изменения и условие завершения. Обратите внимание, что условие окончания функции EXPT1 отличается от условия окончания EXPT2. (Как вы думаете почему?)

Аналогично тому, как предложению LET соответствовало последовательно вычисляющее свои переменные предложение LET*, так и у предложения DO есть свой вариант DO*.

 

 

Предложения PROG, GO, RETURN

На Лиспе можно писать программы и в обычном операторном стиле с использованием передачи управления, как, например, в Фортране. Для этой цели уже в первых Лисп-системах существовало предложение PROG или PROG-механизм (prog feature). Значимость PROG-механизма в программировании уменьшилась в связи с введением в современных Лисп-системах более развитых условных и циклических форм, таких как форма DO, так что использование PROG-механизма в общем-то не рекомендуется. Можно показать, что все выразимое предложением PROG можно записать и с помощью предложения DO и, как правило, в более понятной форме.

С помощью предложения PROG можно:

1. Осуществлять последовательное вычисление форм.

2. Организовывать циклы с помощью команды перехода.

3. Использовать локальные переменные формы.

 

Структура предложения PROG такая же, как и в более старых системах:

 

(PROG (m1 m2 . . . mN)

оператор1

Оператор2

. . .

операторМ)

 

Перечисленные в начале формы переменные mi являются локальными статическими переменными формы, которые можно использовать для хранения промежуточных результатов так же, как это делается при программировании на операторных языках. Если какая-нибудь форма операторi является символом или целым числом, то это метка перехода (tag). На такую метку можно передать управление оператором GO:

 

(GO метка)

GO не вычисляет значение своего «аргумента».

Кроме этого, в PROG-механизм входит оператор окончания вычисления и возврата значения:

 

(RETURN результат)

Операторы предложения PROG вычисляются слева направо (сверху вниз), пропуская метки перехода. Оператор RETURN прекращает выполнение предложения PROG; в качестве значения всего предложения возвращается значение аргумента оператора PROG. Если во время вычисления оператор RETURN не встретился, то значением PROG после вычисления его последнего оператора станет NIL. (Когда PROG-механизм используется для получения побочного эффекта, то возвращаемое значение не играет никакой роли).

Через список переменных можно определить локальные для предложения PROG программные переменные. Перед вычислениями им присваиваются значения NIL. Если переменных нет, то на месте списка переменных нужно оставить NIL. После вычисления значения формы связи программных переменных исчезают так же, как и значения переменных форм LET(*) и DO(*) или как связи формальных параметров лямбда-выражения в вызове функции.

В следующем примере предложение PROG используется для определенной нами ранее через DO функции возведения в степень EXPT:

 

_(defun expt3 (x n)

(PROG (результат)

(setq результат х)

Loop ; метка

(if (= n 1)

(RETURN результат)) ; выход

(setq результат (* результат х))

(setq n (- n 1))

(GO loop))) ` ; передача управления

EXPT3

_(expt3 2 3)

_результат

Error: Unbound atom РЕЗУЛЬТАТ

Это определение явно более громоздко, чем описанные выше версии, основанные на DO.

Механизм передачи управления и предложение RETURN можно использовать наряду с PROG и в некоторых других формах, как, например, DO(*).

Формы GO и RETURN являются примерами статических форм, т.е. они управляют вычислением только в пределах текста определения.

 







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

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