ПАРАДИГМА ФУНКЦІОНАЛЬНОГО ПРОГРАМУВАННЯ 4 страница

Змінна у мові LISP подається символом, а значення прив’язується до символу покажчиком. Прив’язку виконують функцією SET або спеціальною формою SETQ. Символ і його значення це два різних об’єкти. Такий підхід дозволяє вводити динамічну типізацію. Змінна не має типу, тому до символу можна прив’язати значення будь-якого типу.

Крім вказаного поняття змінної, у мові COMMON LISP вводиться узагальнення поняття змінної.

У Common Lisp застосування форми називають „місце”. Форму розуміють, як узагальнену змінну, а результат обчислення форми, як значення змінної. Форма може подаватися тільки у символічному виді і вказує на дане або частину даного.

Застосування форми, як „місця”, дозволяє звертатися до абстрактних вічок, заносити в них дані, заміщувати в них дані або одержувати їх значення. Абстрактним вічком – місцем може бути будь яке дане або частина даного.

Для роботи з узагальненими змінними, що подаються формами COMMON LISP застосовують групу макросів. В цьому розділі ми розглянемо два макроси для прикладу.

7.2 Макроси роботи з місцем

МАКРОС SETF

Привласнювання значення місцю, на яке вказує форма виконується макросом SETF. Макрос може привласнювати значення групі форм і повертає останнє значення, що було привласнено.

Приклад 1:

CL-USER> (setq N '(1 2 3))

(1 2 3)

CL-USER> (setf (car N) 5)

CL-USER> N

(5 2 3)

У прикладі функція Setf заносить число 5 в місце, на яке вказує форма (CAR N). Макрос послідовно обчислює форму:

(CAR N) => (CAR ‘(1 2 3)) => 1

Після чого на місце, де записано число 1 макрос Setf записує число 5.

МАКРОС INCF

Макрос збільшує значення форми(число) на вказане значення. Форма подається у символічному виді. Макрос має необов’язковий параметр. Тому, на скільки треба збільшувати можна не вказувати. По замовчанню значення 1.

CL-USER> (setf V 3)

CL-USER> (incf v)

CL-USER> (incf v 5)

Макрос setf привласнює формі, яка подається символом, число. 3. Перший макрос incf збільшує число 3, що знаходиться у місці, на яке вказує форма v, на 1. Другий макрос incf збільшує число 4, що знаходиться у місці, на яке вказує форма v, на 5.

ТЕМА 8: ФУНКЦІЇ КОМПАРАТОРА

При пошуку даного із певним значенням необхідно перевірити, чи підходить значення даного для певних дій. Для цього у COMMON LISP існує великий набір функцій порівняння значень даних. Слово „компаратор” виникло від англійського слова „compare”, що означає „порівняти”.

Всі функції розділу мають два аргументи і повертають істину, якщо вони порівнюванні по їх тесту, інакше повертають NIL. Кожна функція працює із своїми типами об’єктів.

ФУНКЦІЯ EQ

Достоїнством мови LISP є подавання у середовищі однакових символів і малих цілих чисел один раз. За рахунок вказаного середовище невелике за розміром. В середовищі існують списки символів і малих цілих чисел, у яких інтерпретатор перевіряє наявність вказаних об’єктів.

До малих цілих чисел відносяться числа в діапазоні:

-16777216 <= N <= 16777215

Функція EQ перевіряє чи розташовані об’єкти середовища за однією адресою. Інакше кажучи, функція повертає Т, якщо вказані об’єкти представляють собою один об’єкт.

Приклад 1:

CL-USER> (EQ '\a 'A)

NIL

Перший символ має знак „\”, тому ім’я символу не переводиться у верхній регістр. Тому символи різні.

Приклад 2:

CL-USER> (EQ 'a 'A)

T

Ім’я першого символу переводиться у верхній регістр.

Функція не порівнює числа різних типів та числа, що подаються у різних формах.

Приклад 3:

CL-USER> (EQ 2 2)

T

Числа різних типів зберігаються по різному у середовищі. Дійсне число подаються у вигляді скороченого дробу і має два покажчика на чисельник та знаменник.

CL-USER> (EQ 0.5 2/4)

NIL

Наприклад: 2/4 зберігається, як об’єкт, що має 2 покажчики, що вказують на чисельник 1 та знаменник 2. Дріб 2/4 автоматично скорочується, тому порівнюються числа 1/2 і 0.5.

Числа, що подаються у різних зовнішніх формах також не ідентичні об’єкти.

CL-USER> (EQ 2e+1 20.0)

NIL

У прикладі обидва числа, що порівнюються, дорівнюють 20.

Всі інші типи даних не розташовані за одною адресою.

CL-USER> (eq "r" "r")

NIL

ФУНКЦІЯ EQL

Функція EQL порівнює числа за величиною, не зважаючи на їх величину. У прикладі 1 порівнюються 2 великих цілих.

CL-USER> (EQL 100000000 100000000)

T

Функція не може порівнювати числа різних типів.

CL-USER> (EQL 2.0 2)

NIL

Функція порівнює числа записані у різних формах.

CL-USER> (EQL 2.0 0.2e+1)

T

Функція не може порівнювати складні дані.

CL-USER> (EQL '(1 2 3) '(1 2 3))

NIL

Функція не може порівнювати рядки.

CL-USER> (EQL "Q" "Q")

NIL

Функція може порівнювати символи і знаки.

CL-USER> (EQL 'Q 'Q)

T

CL-USER> (EQL '#\Q '#\Q)

T

ФУНКЦІЯ EQUAL

Функція порівнює дані будь-якого типу, але не порівнює числа різних типів.

CL-USER> (EQUAL '#\Q '#\Q)

T

CL-USER> (EQUAL 'Q 'Q)

T

CL-USER> (EQUAL "Q" "Q")

T

CL-USER> (EQUAL '(1 2 3) '(1 2 3))

T

CL-USER> (EQUAL 2.0 0.2E+1)

T

CL-USER> (EQUAL 2.0 2)

NIL

CL-USER> (EQUAL ‘(2.0 1) ‘(2 1))

NIL

Функція EQUALP

Функція універсальна, її використовують для порівняння будь-яких типів об’єктів і об’єктів, що подаються у різних формах.

CL-USER> (EQUALP '(2.0 1) '(2 1))

T

CL-USER> (EQUALP ‘(1.52e+1 (1 2)) ‘(15.2 (1.0 4/2)) )

T

CL-USER> (EQUALP ‘(1.52e+1 (1 A)) ‘(15.2 (1.0 a)) )

T

Функція = порівнює тільки числа

Для порівняння чисел, що подаються у різних формах запису використовують функцію „=”.

Приклад 1:

У прикладі порівнюються числа різних типів ціле та дійсне.

CL-USER> (= 2 2.0)

Т

Приклад 2:

У прикладі порівнюються числа різних типів звичайний дріб та дійсне.

CL-USER>> (= 1/2 0.5)

Т

Приклад 3:

У прикладі порівнюються дійсні числа, що подаються різними формами запису: з фіксованою точкою і у експоненціональній формі.

CL-USER> (= 1.52e+1 15.2)

Т

Приклад 4:

Функція не може порівнювати символи.

CL-USER> (= ‘A ‘a)

Помилка, повідомлення „Не число”.

Приклад 5:

Проте, наступний приклад вірний, бо А і В змінні.

CL-USER> (Setq A 12.0 B 12)

CL-USER> (= A B)

T

ТЕМА 9: ФУНКЦІЇ ПРЕДИКАТИ

Клас функцій, що перевіряють певний тип об’єкту називають функціями предикатами. Функції мають один аргумент і повертають Т або NIL. Як ознака предикату, більшість назв функцій закінчується буквою „Р”.

ФУНКЦІЯ ATOM

Функція перевіряє, чи є об’єкт атомом.

CL-USER> (atom 23)

T

CL-USER> (atom 1000000000)

T

CL-USER> (atom “qwert”)

T

CL-USER> (atom ‘ASD)

T

CL-USER> (atom '#\q)

T

CL-USER> (atom ‘(1 2 3))

NIL

CL-USER> (atom ‘(q . w))

NIL

ФУНКЦІЯ NUMBERP

Функція перевіряє, чи є об’єкт числом.

CL-USER> (Numberp 2.4)

T

CL-USER> (Numberp “12”)

NIL

ФУНКЦІЯ INTEGERP

Функція перевіряє, чи є об’єкт цілим числом.

CL-USER> (INTEGERP 12)

T

CL-USER> (INTEGERP 12.0)

NIL

CL-USER> (INTEGERP “12.0”)

NIL

ФУНКЦІЯ PLUSP

Функція перевіряє, чи є об’єкт додатнім числом.

CL-USER> (PLUSP 245)

T

CL-USER> (PLUSP -15)

NIL

CL-USER> (PLUSP 0)

NIL

CL-USER> (PLUSP “35”)

Помилка. Не числовий аргумент.

ФУНКЦІЯ MINUSP

CL-USER> (MINUSP -245)

T

CL-USER> (MINUSP 15)

NIL

CL-USER> (MINUSP 0)

NIL

CL-USER> (MINUSP “-6”)

Помилка. Не числовий аргумент.

ФУНКЦІЯ ZEROP

Функція перевіряє, чи є число нулем.

CL-USER> (ZEROP 0)

T

CL-USER> (ZEROP 10)

NIL

CL-USER> (ZEROP “10”)

Помилка. Не числовий аргумент.

ФУНКЦІЯ ODDP

Функція перевіряє, чи є число непарним.

CL-USER> (ODDP 5)

T

CL-USER> (ODDP 10)

NIL

CL-USER> (ODDP “10”)

Помилка. Об’єкт не ціле число.

ФУНКЦІЯ EVENP

Функція перевіряє, чи є число парним.

CL-USER> (EVENP 10)

T

CL-USER> (EVENP 9)

NIL

CL-USER> (EVENP “10”)

Помилка. Об’єкт не ціле.

ФУНКЦІЯ NULL

Функція перевіряє, чи є значенням об’єкту NIL, або чи є об’єкт порожнім списком.

CL-USER> (NULL ‘( ))

T

CL-USER> (NULL ‘(1 3 5))

NIL

CL-USER> (NULL (PLUSP -24))

T

CL-USER> (NULL T)

NIL

CL-USER> (NULL NIL))

T

З останніх двох прикладів видно, що функція працює як логічна функція NOT:

CL-USER> (NOT T)

NIL

CL-USER> (NOT NIL)

T

ТЕМА 10: СУВОРО ФУНКЦІОНАЛЬНИЙ І ІМПЕРАТИВНИЙ МЕТОДИ ПРОГРАМУВАННЯ

10.1 Методи реалізації послідовних операцій

При суворо функціональному методі програмування функція користувача являє собою одну складну функцію, що написана методом суперпозиції.

Наприклад, нехай треба написати функцію, що обчислює вираз

X2 + Y2:

CL-USER> (defun s (X Y)(+ (* X X) (* Y Y)))

S

CL-USER>(Setq N (s 10 20) )

Функція має виклики функцій „+” і „*”. Функція „*” є внутрішньою функцією для функції „+”, вона обчислює аргументи функції „+” і розміщує їх на місце своїх викликів. В результаті функція „+” буде мати аргументи: (+ 100 400).

Результат роботи функції „+” повертається також на місце її виклику і привласнюється змінні N.

При імперативному методі програмування(операторному) функція записується послідовністю викликів, що веде до результату.

Функція, що обчислює той же вираз імперативним методом, запишеться:

CL-USER> (defun s (X Y) (setq R1 (* X X)) (setq R2 (* Y Y)) (+ R1 R2))

S

CL-USER> (s 10 20)

На практиці методи часто комбінуються. При суворо функціональному методі програмування операції, що повторюються реалізуються тільки рекурсією. При імперативному методі програмування операції, що повторюються, реалізуються циклічними конструкціями.

Програма на мові Лісп подається ієрархічною структурою з функцій користувача, що пов’язані між собою викликами. У програмі є головна функція, з якої викликаються інші функції, а кожна функція в свою чергу може містити виклики інших функцій.

Іноді програма містить окремі функції, кожна з них застосовується користувачем окремо.

10.2 Блочна організація функції

Функція може складатися з декількох блоків. Блочна структура функції дозволяє іменувати групу форм міткою і керувати виконанням блоків. Застосовуючи блочну організацію функції можна завершувати блок при певних умовах.

Для створення блоку використовують спеціальну форму Block, яка працює в парі з функцією Return - from.

(Block Мітка форма1 форма2 форма3 ... формаN)

(Return-from Мітка об’єкт)

Форми тіла спец. форми Block виконуються послідовно до тих пір, поки не виконається певна умова, тоді функцією Return-from закінчують виконання форм блоку і повертається значення об’єкту. Якщо умова не виконана, то форми блоку виконуються до кінця і повертається результат останньої форми.

Розглянемо приклад застосування блоку: Нехай треба вводити різні типи даних і оброблювати їх залежно від типу.

CL-USER> (defun R () (block numb (setq N (read) )

(if (Not(numberp N)) (return-from numb ))

(setq N (+ N 15))(return-from R N ))(block list (reverse N)))

R

CL-USER> (R)

CL-USER> (R)

(2 4 6)

(6 4 2)

Блок numb оброблює числа, а блок list оброблює списки.

10.3 Типи змінних

У Common Lisp існує три типи змінних: постійні, лексичні, динамічні.

Постійні змінні –це іменовані константи. Їх можна визначити макросом Defconstant, їх дія все середовище.

CL-USER> (defconstant mes 12)

MES

CL-USER> (/ mes 4)

CL-USER> (setq mes 2)

Помилка „Константі не можна привласнювати значення”.

Лексичні та динамічні змінні тільки приблизно відповідають локальним та глобальним змінним у інших мовах програмування. При роботі із змінними у Common Lisp змінним не привласнюється значення, змінюється тільки покажчик на інший об’єкт. Сам об’єкт на який вказував покажчик раніше не змінюється.

Імена у Common Lisp складають лексичний простір. До кожної лексичної змінної може бути прив’язано одно або декілька значень. Але кожна прив’язка має свою область дії.

Формальні параметри функції являють собою лексичні змінні, до яких прив’язуються значення фактичних параметрів під час виклику функції. Формальні параметри називають також статичними лексичними змінними. Їх прив’язка працює тільки у тій формі, де вони визначені. Тобто на лексичні змінні можна посилатися тільки із форми, де вони визначені.

Розглянемо приклад з статичною лексичною змінною N.

CL-USER> (setq N 31)

CL-USER> (defun R (N) (LIST N 25 17))

R

CL-USER> (R 4)

(4 25 17)

CL-USER> N

Статична N працює тільки при роботі функції R.

Якщо у визначенні функції є виклик іншої функції, визначення якої лежить зовні першої функції, то лексична змінна у другому визначенні не працює.

Наприклад:

CL-USER> (Defun R2 (D) (Print (Reduce 'MAX D)))

R2

CL-USER> (Defun R1 (D) (Princ(+ (R2 '(2 7 3)) D )))

R1

CL-USER> (R1 13)

 

7 20

Друкується значення форми, що знаходить максимальний елемент списку. Форма має аргументом статичну лексичну змінну D з функції R2 із значенням (2 7 3). Функція МАХ має аргументами числа, а функція Reduce застосовує функцію МАХ до списку чисел.

Далі друкується сумма максимального елемента списку і значення статичної лексичної змінної D з функції R1 із значенням 13. Результат, що повертає функція R1 число 20.

До лексичних змінних відносять також змінні, що створюються спеціальною формою LET.

(LET ((змінна1 значення1) (змінна2 значення2)…) форма1 форма2 ... форма N)

Змінні із прив’язками у спец. формі LET існують тільки при роботі форм у тілі LET. Спец. форма повертає значення останньої виконаної форми.

Наприклад: Нехай треба знайти суму першого і останнього елементів списку.

CL-USER> (Defun Sum (L) (LET ((S (CAR L)) ) (+ S (CAR (LAST L))) ) )

SUM

CL-USER> (sum '(2 4 6))

У прикладі змінна S одержує початкове значення 2. Змінна S існує поки працює форма LET.

Функція LAST одержує останній конс списку (6), а функція CAR вибирає останній елемент списку 6.

Лексичні статичні змінні ми ще зустрінемо у формах типу DO. Ці форми також застосовують свої лексичні статичні змінні.

Лексичні статичні змінні формуються у стеку, їх називають локальними змінними.

Динамічні змінні, що існують у середовищі, називають глобальними. На них можна посилатися у будь-який час та з будь-якої програми. З одним і тим же ім’ям можуть існувати динамічна змінна і лексичні змінні, але кожна у своєму лексичному середовищі.

ТЕМА 11: РЕКУРСІЯ

Слово рекурсія означає повторне виконання дій. Термін походить від слова „курсувати”. Рекурсивними можуть бути як дані, так і процедури. Ми будемо розглядати рекурсивні дані типу SEQUENCE.

Дані називаються рекурсивними, якщо після відділення якоїсь частини даного, дане залишається того ж типу.

Наприклад, список (1 2 3 4 5) рекурсивне дане. Хвіст списку (CDR ‘(1 2 3 4 5) також список. Рекурсивні типи даних зручно оброблювати рекурсивними процедурами.

Функція називається рекурсивною, якщо в її тілі знаходиться виклик себе або вона викликає іншу функцію, у якій є виклик першої функції. Рекурсивні функції обов'язково мають граничну умову і рекурсивну умову. Без граничної умови рекурсія буде не результативною. Причому, аргументи рекурсивного виклику повинні обов’язково сходитися до аргументів граничної умови.

Рекурсивні методи бувають 2-х типів:

Ø Висхідний метод рекурсії.

Ø Низхідний метод рекурсії.

Висхідна рекурсія має одну фазу – фазу одержання рішення. Низхідна рекурсія має дві фази: фазу редукції і фазу одержання рішення.

ВИСХІДНИЙ МЕТОД РЕКУРСІЇ

Розглянемо приклад рекурсивної функції, що написана висхідним методом.

Приклад 1: Побудувати список, елементи якого розташовуються у зворотному порядку.

Схема реалізації завдання висхідним методом:

№ рівня М N

1 ß (1 2 3) ß NIL

2 ß (2 3) ß (1)

3 ß (3) ß (2 1)

4 .NIL .(3 2 1)

Реалізуємо цю функцію методом висхідної рекурсії.

CL-USER> (DEFUN Rev (M N)

( COND ((Null M) N) ((Rev (CDR M) (Cons (car M) N) ) )) )

REV

CL-USER> (REV '(1 2 3) NIL)

(3 2 1)

Вся функція – це спеціальна форма COND, перша пара якої містить перевірку на кінець списку, а друга пара містить рекурсивний виклик функції із зміненими аргументами.

Якщо список не порожній, то умова першої форми не виконується. Тоді виконується друга форма. Друга форма містить тільки умову – рекурсивний виклик. Як показано раніше, у такому випадку результатом виконання форми є результат умови.

При кожному рекурсивному виклику функції старий список зменшується на один елемент, а новий список збільшується на цей елемент.

НИЗХІДНИЙ МЕТОД РЕКУРСІЇ

Низхідний метод рекурсії реалізується двома фазами: фазою редукції і фазою одержання рішення.

Метод редукції – це спрощення задачі за рахунок декомпозиції її на більш прості задачі. На фазі редукції аргументи рекурсивного виклику сходяться до аргументів граничної умови.

Фаза одержання рішення поступово компонує рішення основної задачі з рішень більш простих задач.

Реалізуємо теж саме завдання низхідним методом.

Схема реалізації завдання низхідним методом:

№ рівня M Результат

1 ß (1 2 3) . (3 2 1)

2 ß (2 3) Ý (3 2)

3 ß (3) Ý (3)

4 .( ) Ý NIL

CL-USER> (DEFUN Rev (M ) ( COND ((Null M) NIL ) ((Append (Rev (CDR M) ) (LIST (CAR M) )) )))

REV

CL-USER> (rev '(1 2 3))

(3 2 1)

Для функції, що написана низхідним методом, потрібен тільки список. Як у попередній функції вся функція – це спеціальна форма COND, перша пара якої містить перевірку на кінець списку, а друга пара містить дії, що задані другою парою.

Рекурсивний виклик функції із зменшеним списком на один елемент реалізує фазу редукції.

По досягненню граничної умови(список порожній) починається фаза одержання рішення. На кожному рівні в кінець списку додається перший елемент списку.

ТЕМА 12: КОНСТРУКЦІЇ, ЩО КЕРУЮТЬ

Будемо називати конструкціями, що керують, форми, які змінюють порядок виконання форм програми певним чином. Конструкції, що керують, бувають наступних типів:

1) Робота з контекстом.

2) Послідовного виконання.

3) Розгалужених обчислень.

4) Ітерації.

5) Передачі керування обчисленням.

6) Динамічного керування обчисленням

12.1 Спеціальна форма QUOTE

Спеціальна форма QUOTE відноситься до типу конструкцій робота з контекстом. Під контекстом розуміють середовище. Спеціальна форма впливає на процедуру обчислення інтерпретатору, забороняючи обчислення певних функцій і об’єктів середовища.

CL-USER> '(+ 12 13)

(+ 12 13)

12.2 Спеціальна форма PROGN

(Progn Форма1 Форма2 … Форма N)застосовується для визначення набору функцій, як єдиного цілого. Форма відноситься до типів конструкцій послідовного виконання.

Вона примушує виконати форми, що розташовані в її тілі послідовно зліва направо і повертає значення, яке обчислює остання форма.Аналогом Prognє операторні дужки „begin end” у мові Паскаль.

Приклад 1:

CL-USER>(Defun s () (Progn (Setq K (+ 3 4)) (Print K) (CAR ‘(1 2 3))) )

s

CL-USER>(s)

 

Загальний принцип:будь-яке значення крім логічної константи NIL вважається істинним значенням. Це дозволяє у конструкціях, що керують, результат будь-якої форми застосовувати як логічне значення.

12.3 Спеціальна форма COND

Спеціальна форма Condзастосовується для виконання певних дій за умовами. Спеціальна форма відноситься до типу розгалуження обчислень.

Спец. форма подається: (Cond пара1 пара2 …параN).

Кожна пара подається: (умова форма).

Спеціальна форма COND переглядає пари зліва направо, перевіряючи умови кожної пари. Якщо умова пари має місце, то обчислюється форма пари і результат повертається. Наступні пари не розглядаються.

Якщо умова пари не виконується, то обирається наступна пара. Якщо умови всіх форм не виконуються, то повертається NIL.

Приклад 1:

CL-USER> (defun s (R) (cond ((minusp R) 1)((plusp R)2)))

S

CL-USER> (s 0)

NIL

Якщо при виконанні умови пари треба виконати декілька дій, то застосовується функція PROGN для об’єднання дій в єдине ціле.

Приклад 2:

Вводиться число і перевіряється його ознака. Якщо число додатне, то виводиться слово PLUS. Якщо число нуль, то виводиться слово ZERO. Інакше виводиться слово MINUS. Якщо вводиться не число, функція закінчує свою роботу за помилкою.

Приклад 3:

CL-USER> (defun P ()(Princ "Number?")(setq N (read))

(COND ((Plusp N)(Princ "PLUS"))((Zerop N)(Princ "ZERO"))

(T (PRINC "MINUS"))))

P

CL-USER> (P)

"Number?" 2

PLUS

"PLUS"

Пара з умовою Т є пасткою для умов, які не перелічено у функції COND. Результат виводиться двічі: один раз функцією Princ, другий раз як результат функції Р.

У якості умови може бути будь-яка функція або константа, бо будь-який результат істинний, крім NIL.

Приклад 4:

CL-USER> (defun P () (Print "1 2 3 ?") (setq N (read)) (cond (1 (Princ "one")) (2 (Princ "two"))))

P

CL-USER> (P)

 

“1 2 3 ?” 2

one

"one"

У функції умова один є пасткою, вона завжди істина, тому друга пара не працює.

У парі може бути тільки умова, тоді повертається тільки результат умови.

Приклад 5:

CL-USER> (defun P () (Print "1 2 3 ?") (setq N (read)) (cond (2)))

P

CL-USER> (P)

 

"1 2 3 ?" 1

Умова пари 2 –істина. Форма пари відсутня, тому повертається 2 незалежно від того, що введено.

Часто в програмах треба застосовувати тільки одну пару для виходу з функції. В цьому випадку парою COND повинна бути:

(умова (return-from Name Object) ).

Приклад 6:

Нехай треба знайти суму елементів числового списку. Розв’яжемо цю задачу методом рекурсії.

CL-USER> (Defun sum (N S)

(COND ((NULL N) (return-from sum S)) )

(setq S (+ (CAR N) S))

(sum (CDR N) S) )

SUM

CL-USER> (sum '(1 2 3) 0)

Функція (return-from Name Object) завершує виконання функції і повертає вказаний об’єкт. У нашому випадку завершується виконання функції SUM і повертається сума елементів списку S.

12.4 Спеціальна форма IF

Спеціальна форма IF відноситься до типу розгалуження обчислень.

Спеціальна форма IF – залежно від істинності умови обчислює THEN- форму або ELSE-форму:

(IF умова THEN-форма ELSE-форма)

Слова THEN та ELSE не пишуться. Формою THEN або ELSE може бути тільки одна форма. Щоб виконати декілька форм застосовують спеціальну форму PROGN.

Наприклад:

CL-USER> (DEFUN Sp (R)

(IF (NUMBERP R) (PROGN (setq R (/ R 2) )(PRINC R) )

(PROGN (setq R (Reverse R))(Princ R) ) ))

SP

CL-USER> (sp "kot")

tok

"tok"

Функція REVERSE працює з даними типу SEQUNCE. Вона записує елементи рядку або списку у зворотному порядку.

12.5 Макрос DO

Макрос DO застосовується для реалізації операцій, що повторюються, операторним методом.

(DO ( (Змінна Значення) ... (Змінна Значення))

(умова_ закінчення результат) Форма1 ... ФормаN)

Перед початком роботи макросу DO лексичним статичним змінним надають початкові значення, що будуть застосовуватись у циклі при обчисленні форм. На кожній ітерації програміст сам повинен змінювати значення змінних. Після закінчення роботи циклу статичні змінні знищуються.

DOорганізує повторне обчислення форм, що розташовані в тілі DO зліва направо. Перша форма є умовою закінчення роботи циклу. Коли умова закінчення циклу стане істиною, тоді повертається результат. Інакше обчислюються наступні форми.

Розглянемо приклад1. Ввести числовий список. Одержати суму елементів списку.

CL-USER> (DEFUN SUM (L)

(DO ( (S 0) )

((NULL L) S)

(SETQ S (+ S (CAR L) ) L (CDR L) ) ) )

CL-USER> (SUM ‘(1 2 3 4))

У виразі ( (NULL L) S) дві дужки підряд означають неявну форму COND. Запис тотожній такому: (COND ( (NULL L) S) )

Якщо при виклику функції треба зробити кількість фактичних параметрів менше кількості формальних параметрів, то формальним параметрам, що не одержують значення, привласнюється значення у списку локальних змінних.

Приклад2: Ввести числовий список. Утворити новий список, записавши елементи введеного списку у зворотному порядку.

CL-USER> (DEFUN REV (L1)

(DO ( (L2 NIL) )

( ( NULL L1) L2)

(SETQ L2 (CONS (CAR L1) L2) L1 (CDR L1) ) ) )

CL-USER> (rev ‘(1 2 3 4))

(4 3 2 1)

Замість значення локальної змінної можна задавати форму, що обчислює значення. Розглянемо приклад.

Приклад3. Ввести числовий список. Утворити новий список, елементи якого записано у зворотному порядку, а останнім елементом якого є довжина списку.

CL-USER> (Defun sum1 (L)

(DO ( (L2 (LIST (Length L) ) ) )

( (NULL L) L2)

(SETQ L2 (CONS (CAR L) L2))

(SETQ L (CDR L) ) ) )

CL-USER>(Sum ‘(1 2 3 4))

(4 3 2 1 4)

Крім вказаного загального макросу DO існують спеціалізовані макроси DOTIMES і DOLIST.

DOTIMES

Макрос DOTIMES: у загальному вигляді подається:

(dotimes (змінна лічильник) форма1 форма2 ...формаN)

Змінна автоматично нарощується від 0 до вказаного цілого значення лічильника. Замість цілого числа можна задавати форму, що повертає ціле число. Макрос завжди повертає NIL.

CL-USER> (dotimes (i 10)(Princ i) )

NIL

CL-USER> (dotimes (i 10)(Princ 'd) )

DDDDDDDDDD

NIL

CL-USER> (dotimes (i 10) (format t "~d " i))

0 1 2 3 4 5 6 7 8 9

NIL

CL-USER> (dotimes (i 10)(Princ "Number:") (format t "~d " i))

Number:0 Number:1 Number:2 Number:3 Number:4 Number:5 Number:6 Number:7 Number:8 Number:9

NIL

CL-USER> (dotimes (i 10) (format t "~f " i))

0.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0

NIL

(dotimes (i 10)(if (oddp i)(setq k T )(setq k nil)) (format k "~f " i))

1.0 3.0 5.0 7.0 9.0

NIL

DOLIST

Макрос DOLIST: у загальному вигляді подається:

(dotimes (змінна список) форма1 форма2 ...формаN)

Макрос послідовно рухається за елементами списку і виконує над ними дії, що вказані у формах. Макрос завжди повертає NIL.

CL-USER> (dolist (i '(2 4 6)) (princ i))

NIL

CL-USER> (setq s 0)(dolist (i '(2 4 6)) (princ i)(incf s i))

NIL

CL-USER> s

12.6 Макрос LOOP

Слово LOOPс англійськоїперекладається як петля. Макрос LOOP застосовують для виконання операцій, що повторюються, операторним методом.

Макрос LOOP буває двох типів простий і розширений. Ми будемо розглядати простий тип.

Простий тип LOOP виконує послідовно форми зліва направо. Після закінчення форм виконання форм повторюються. Серед форм повинна бути форма, що містить граничну умову. Якщо умова істина, то макрос Loop закінчує виконання форм.








Дата добавления: 2016-09-20; просмотров: 568;


Поиск по сайту:

При помощи поиска вы сможете найти нужную вам информацию.

Поделитесь с друзьями:

Если вам перенёс пользу информационный материал, или помог в учебе – поделитесь этим сайтом с друзьями и знакомыми.
helpiks.org - Хелпикс.Орг - 2014-2024 год. Материал сайта представляется для ознакомительного и учебного использования. | Поддержка
Генерация страницы за: 0.149 сек.