ПАРАДИГМА ФУНКЦІОНАЛЬНОГО ПРОГРАМУВАННЯ 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; просмотров: 621;