Определения форм FLET, LABELS
(flet (<binding>...) <expr>)
(labels (<binding>...) <expr>)
<binding> - функциональные связи, каждая из которых имеет вид (<sym> <farg> <body>) <sym> - имя локальной функции <farg> - список формальных параметров <body> - тело локальной функции <expr> - вычисляемое выражение формы, содержащее вызовы локальных функций. Labels используется в рекурсивном случае. Накапливающие параметры
Стандартное определение факториала (n! = 1*2*3*…*n): (defun! (n) (if (= n 0) 1.0 (* n (! (1- n)))) )
При больших n стек будет переполнен. В следующем определении используется метод накапливающего параметра. Определена локальная функция fac, у которой второй аргумент служит для накопления результата.
(defun! (n) (labels ((fac (x y) (if (zerop x) y (fac (1- x) (* x y)))) ) (fac n 1.0)) )
Нахождение наибольшего общего делителя двух чисел
(defun gcd (n m) (let ((r (rem n m))) (if (zerop r) m (gcd m r))))
Вычисление суммы и произведения элементов списка
; 1 вариант ; программирование "в лоб"
(defun sumpr (x) (if (null x) (list 0 1) (list (+ (first x) (first (sumpr (rest x)))) (* (first x) (second (sumpr (rest x)))))) )
; 2 вариант ; использование let
(defun sumpr (x) (if (null x) (list 0 1) (let ((z (sumpr (rest x)))) (list (+ (first x) (first z)) (* (first x) (second z))))) )
; 3 вариант ; еще одно использование let
(defun sumpr (x) (if (null x) (list 0 1) (let ((n (first x)) (z (sumpr (rest x)))) (list (+ n (first z)) (* n (second z))))) )
; 4 вариант ; еще одно использование let
(defun sumpr (x) (if (null x) (list 0 1) (let ((n (first x)) (z (sumpr (rest x)))) (let ((a (first z)) (b (second z))) (list (+ n a) (* n b))))) )
; 5 вариант ; использование накапливающих параметров
(defun sumpr (x) (sp x 0 1))
(defun sp (x s p) (if (null x) (list s p) (sp (rest x) (+ (first x) s) (* (first x) p))) )
; 6 вариант ; использование локальной функции
(defun sumpr (x) (labels ((sp (y s p)
(if (null y) (list s p) (sp (rest y) (+ s (first y)) (* p (first y)))))) (sp x 0 1)) ) МАТЕМАТИЧЕСКИЕ ОСНОВЫ: l-ИСЧИСЛЕНИЕ
l-исчисление было использовано как средство для описания (чисто синтаксического) свойств математических функций и эффективной обработки их в качестве правил. Функциональные программы построены из “чистых” функций, т. е. функций в математическом смысле, и поэтому нотация l-исчисления особенно удобна для формального описания манипулирования функциями и даже в качестве промежуточного кода, в который можно транслировать исходную программу. В действительности функциональные языки программирования часто представляют собой “улучшенные” версии нотации l-исчисления в том смысле, что все функциональные программы можно преобразовать в эквивалентные l-выражения. Хотя нотация l-исчисления проста, она является достаточно мощной, чтобы описать все черты исходного функционального языка. Введение в синтаксис
l-исчисление можно рассматривать как язык программирования, хотя оно было создано (Чёрч) в 20-х годах нашего века в период философских исследований в области оснований математики. Главная особенность заключается в том, что оно является языком высшего порядка, т. е. в нём имеются средства описания функций, входные и выходные значения которых также могут быть функциями. Кроме того, оно основано не на концепции множества, как многие другие математические языки, а на понятии функции. Работая в направлении автоматизации значительной части математического и логического интеллекта, программисты-теоретики сталкиваются с теми же проблемами над которыми логики ломают голову уже 80 лет (например, что такое математическое мышление и как его формализовать?). Поэтому их исследования могут служить полезным источником для программистов. Два подхода к функциям 1. Дирихле: функция задается графиком - множеством пар < аргумент, значение>.
2. Функция – правило, вычислительное предписание. С первой точки зрения x^2-4 и (x+2)*(x-2) - разные обозначения одной и той же функции; со второй точки зрения – это разные функции. Обычная запись f(x) может обозначать как обозначение функции, так и вызов функции с аргументом x. Для более строгого подхода это необходимо различать. Для этого вводятся ламбда-обозначения. Например, x^2+3 - некоторая функция, зависящая от x. Ламбда-обозначение для этой функции lx. x^2+3. Этой записи соответствует правило: для любого a (lx. x^2 +3) (a) = a^2+3
Выражение x + 2y можно считать как функцию от x (записывается lx. x +2y) и как функцию от y (записывается ly. x +2y). (lx. x +2y) a ® a+2y (ly. x +2y) a ® x+2a
Запись ly.lx.E понимается как ly.(lx. E). Поэтому ((ly.lx. x+2y) a) b ® (lx. x+2a) b ® b+2a ((lx.ly. x+2y) a) b ® (ly. a+2y) b ® a+2b
Мы читаем символ l как “функция от” и точку (.) как “которая возвращает”. Определение l-термов · Каждая переменная есть l-терм. · Каждая константа есть l-терм. · По любым l-термам M и N можно построить новый l-терм (M N) (обозначающий применение, или аппликацию, оператора M к аргументу N). · По любой переменной x и любому l-терму M можно построить новый l-терм (lx.M) (обозначающий функцию от x, определяемую l-термом M). Такая конструкция называется l-абстракция. Попросту говоря, l-исчисление - это исчисление анонимных (безымянных) функций. Символ x после l называется связанной переменной абстракции и соответствует понятию формального параметра в традиционной процедуре или функции. Выражение справа от точки называется телом абстракции, и, подобно коду традиционной процедуры или функции, оно описывает, что нужно сделать с параметром, поступившим на вход функции. Тело абстракции может быть любым допустимым l-выражением, и поэтому оно также может содержать другую абстракцию, например: lx. ly. (x+y)*2 Это выражение читается как “функция от x, которая возвращает функцию от y, которая возвращает (x+y)*2. Используется соглашение: запись (...(((lx1. lx2.... lxn. E) a1) a2)...an) кратко пишется как (lx1. lx2.... lxn. E) a1 a2...an Для полноты опишем ламбда-нотацию более формально в виде БНФ: <выражение>::= l<идентификатор>. <выражение> | <идентификатор> | <выражение> <выражение> | (<выражение>) | <константа>
Набор констант произволен: целые числа, булевы константы, арифметические операции, булевы функции и т. п. Вычисление l-выражений
Мы рассмотрели, как l-нотация может быть использована для представления функциональных выражений и сейчас готовы к тому, чтобы определить правила вывода l-исчисления, которые описывают, как вычислять выражение, т. е. как получать конечное значение выражения из его первоначального вида. Константы являются самоопределенными, т. е. их невозможно преобразовать в более простые выражения. Применение константной функции записывается в виде встроенных соответствующих d-правил, например + 1 3 ®d 4 Процесс упрощения выражений называется редукцией. Пример редукции (®d – обозначение δ-редукции): * (+ 1 2) (- 4 1) ®d * (+ 1 2) 3 ®d * 3 3 ®d 9 Правило редукции как применять l-абстракцию: копируется тело абстракции с заменой всех вхождений связанной переменной на выражения аргумента - называется b-редукцией (обозначается ®b или просто ®). (lx. * x x) 2 ®b * 2 2
((lx. ly. + x y) 7) 8 ® (ly. + 7 y) 8 ® + 7 8 ® 15
Редуцируемое выражение называется редексом, и мы можем на данном этапе заключить, что процесс редукции ламбда-выражения состоит из множества редукций, применяемых к редексам данного выражения до тех пор, пока выражение включает в себя хотя бы один редекс. В зависимости от того, какое правило можно применить к редексу, используются понятия b-редекса и d-редекса. При выполнении b-редукции следует быть внимательными и не выполнять подстановку в тело абстракции, если связанная переменная этой абстракции имеет такое же имя, как и заменяемая переменная: lx. (lx. x) (+ 1 x)
(lx. (lx. x) (+ 1 x)) 1 ® (lx. 1) (+ 1 1) ® (lx. 1) 2 ® 1 Ошибка!
В этом случае нужно оставить такую (внутреннюю) абстракцию без изменений. Возможно также переименовать переменную - алфавитно-эквива-лентное преобразование. Правильно: (lx. (lx. x) (+ 1 x)) 1 ® (lx. x) (+ 1 1) ® (lx. x) 2 ® 2
Примеры редукции выражений (используемые редексы подчеркнуты):
1)
(lf. lx. f 4 x) (ly. lx. + x y) 3 ® (lx. (ly.lx. + x y) 4 x) 3 - выбрали один из двух возможных редексов
® (ly. lx. + x y) 4 3 ® (lx. + x 4) 3 ® + 3 4 ® 7
2)
(lf. lx. f 4 x) (ly. lx. + x y) 3 ® (lx. (ly.lx. + x y) 4 x) 3 - выбрали один из двух возможных редексов ® (lx. (lx. + x 4) x) 3 - снова делаем произвольный выбор ® (lx. + x 4) 3 ® + 3 4 ® 7
Воспользуйтесь поиском по сайту: ©2015 - 2024 megalektsii.ru Все авторские права принадлежат авторам лекционных материалов. Обратная связь с нами...
|