Вы находитесь на странице: 1из 42

Функциональное программирование

Шевченко Александр Сергеевич

2 октября 2009 г.

Шевченко Александр Сергеевич () Функциональное программирование 2 октября 2009 г. 1 / 42


Содержание

1 Элементы функционального программирования


Введение в функциональное программирование
Введение в язык Haskell

2 Средства функционального программирования


Функции высших порядков

Шевченко Александр Сергеевич () Функциональное программирование 2 октября 2009 г. 2 / 42


Содержание

1 Элементы функционального программирования


Введение в функциональное программирование
Введение в язык Haskell

2 Средства функционального программирования


Функции высших порядков

Шевченко Александр Сергеевич () Функциональное программирование 2 октября 2009 г. 2 / 42


Элементы функционального программирования Введение в функциональное программирование

Функциональное программирование ставит своей целью придать каждой программе


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

Лоренс Паулсон

В 40-х годах XX века появились первые цифровые компьютеры и создание всевозможных


ассемблерных языков с простой мнемоникой. Императивные языки высокого уровня
(BASIC, Pascal, C, Ada и прочие, включая объектно-ориентированные).

Шевченко Александр Сергеевич () Функциональное программирование 2 октября 2009 г. 3 / 42


Элементы функционального программирования Введение в функциональное программирование

Подведение итогов

1 Императивные языки служат для описания процессов; функциональные – для


описания функций, вычисляющих результат по исходным данным.
2 На традиционных языках можно писать в функциональном стиле, однако средств
работы с функциями в традиционных языках недостаточно.
3 Традиционные способы реализации языков программирования плохо подходят для
программ, написанных в функциональном стиле.
4 Традиционные языки не могут обеспечить удобных средств для распараллеливания
вычислений: последовательное выполнение команд – узкое место традиционной
архитектуры компьютеров («фон-Неймановское горлышко»).
5 Для функционального программирования требуются специализированные языки

Шевченко Александр Сергеевич () Функциональное программирование 2 октября 2009 г. 4 / 42


Элементы функционального программирования Введение в функциональное программирование

Свойства функциональных языков

В качестве основных свойств функциональных языков кратко рассмотрим следующие:


краткость и простота;
строгая типизация;
модульность;
функции - это значения;
чистота (отсутствие побочных эффектов);
отложенные (ленивые) вычисления.

Шевченко Александр Сергеевич () Функциональное программирование 2 октября 2009 г. 5 / 42


Элементы функционального программирования Введение в функциональное программирование

Свойства функциональных языков

Краткость и простота. Программы на функциональных языках обычно намного короче и


проще, чем те же самые программы на императивных языках.
Пример 1. Быстрая сортировка Хоара на C.

void quickSort ( int a [] , int l , int r)


{
int i = l ;
int j = r ;
int x = a [( l + r ) / 2];
do
{
w h i l e ( a [ i ] < x ) i ++;
w h i l e ( x < a [ j ] ) j −−;
i f ( i <= j )
{
i n t temp = a [ i ] ;
a [ i ++] = a [ j ] ;
a [ j −−] = temp ;
}
}
w h i l e ( i <= j ) ;
i f ( l < j ) quickSort (a , l , j );
i f ( i < r ) quickSort (a , i , r );
}

Шевченко Александр Сергеевич () Функциональное программирование 2 октября 2009 г. 6 / 42


Элементы функционального программирования Введение в функциональное программирование

Свойства функциональных языков

Пример 2. Быстрая сортировка Хоара на абстрактном функциональном языке.

quickSort ([]) = []
quickSort ([ h : t ]) = quickSort (n | n t , n <= h ) + [ h ] + q u i c k S o r t (n | n t , n > h)

Пример 2 следует читать так:


1. Если список пуст, то результатом также будет пустой список.
2. Иначе (если список не пуст) выделяется голова (первый элемент) и хвост (список из
оставшихся элементов, который может быть пустым). В этом случае результатом будет
являться конкатенация (сращивание) отсортированного списка из всех элементов хвоста,
которые меньше либо равны голове, списка из самой головы и списка из всех элементов
хвоста, которые больше головы.
Пример 3. Быстрая сортировка Хоара на языке Haskell.

quickSort [] = []
quickSort (h : t ) = quickSort [y | y <− t , y < h ] ++ [ h ] ++ q u i c k S o r t [y | y <− t , y >= h ]

Шевченко Александр Сергеевич () Функциональное программирование 2 октября 2009 г. 7 / 42


Элементы функционального программирования Введение в функциональное программирование

Свойства функциональных языков

Модульность. Механизм модульности позволяет разделять программы на несколько


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

s q u a r e (N) = N ∗ N
s q u a r e L i s t = map ( s q u a r e , [1 , 2, 3, 4])

Результатом выполнения этой инструкции будет список [1, 4, 9, 16].


Чистота (отсутствие побочных эффектов). Пример. Глобальные и локальные переменные.
Отложенные вычисления. Если функциональный язык не поддерживает отложенные
вычисления, то он называется строгим.
Примеры строгих языков: Scheme, Standard ML и Caml.
Языки, использующие отложенные вычисления, называются нестрогими. Haskell - нестрогий
язык, так же как, например, Gofer и Miranda. Нестрогие языки зачастую являются чистыми.

Шевченко Александр Сергеевич () Функциональное программирование 2 октября 2009 г. 8 / 42


Элементы функционального программирования Введение в функциональное программирование

Решаемые задачи

В качестве задач, традиционно рассматриваемых в курсах функционального


программирования, можно выделить следующие:
1 Получение остаточной процедуры. Если даны следующие объекты:
P (x1, x2, ..., xn) - некоторая процедура.
x1 = a1, x2 = a2 - известные значения параметров.
x3, ..., xn - неизвестные значения параметров.
Требуется получить остаточную процедуру P1 (x3, ..., xn). Эта задача решается только
на узком классе программ.
2 Построение математического описания функций. Пусть имеется программа P. Для неё
определены входные значения и выходные значения . Требуется построить
математичекое описание функции f : Dx1, ..., Dxn -> Dy1, ..., Dym.
3 Определение формальной семантики языка программирования.
4 Описание динамических структур данных.
5 Автоматическое построение "значительной"части программы по описанию структур
данных, которые обрабатываются создаваемой программой.
6 Доказательство наличия некоторого свойства программы.
7 Эквивалентная трансформация программ.

Шевченко Александр Сергеевич () Функциональное программирование 2 октября 2009 г. 9 / 42


Элементы функционального программирования Введение в функциональное программирование

Справочный материал

Lisp (List processor). Считается первым функциональным языком программирования.


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

ISWIM (If you See What I Mean). Функциональный язык-прототип. Разработан Ландиным в 60-х
годах XX века для демонстрации того, каким может быть язык функционального
программирования. Вместе с языком Ландин разработал и специальную виртуальную машину для
исполнения программ на ISWIM’е. Эта виртуальная машина, основанная на вызове-по-значению,
получила название SECD-машины. На синтаксисе языка ISWIM базируется синтаксис многих
функциональных языков. На синтаксис ISWIM похож синтаксис ML, особенно Caml. Scheme.
Диалект Lisp’а, предназначенный для научных исследований в области computer science. При
разработке Scheme был сделан упор на элегантность и простоту языка. Благодаря этому язык
получился намного меньше, чем Common Lisp.

ML (Meta Language). Семейство строгих языков с развитой полиморфной системой типов и


параметризуемыми модулями. ML преподается во многих западных университетах (в некоторых
даже как первый язык программирования).

Standard ML. Один из первых типизированных языков функционального программирования.


Содержит некоторые императивные свойства, такие как ссылки на изменяемые значения и поэтому
не является чистым. При вычислениях использует вызов-по-значению. Очень интересная
реализация модульности. Мощная полиморфная система типов. Последний стандарт языка -
Standard ML-97, для которого существует формальные математические определения синтаксиса, а
также статической и динамической семантик языка.

Шевченко Александр Сергеевич () Функциональное программирование 2 октября 2009 г. 10 / 42


Элементы функционального программирования Введение в функциональное программирование

Справочный материал

Caml Light и Objective Caml. Как и Standard ML принадлежит к семейству ML. Objective Caml
отличается от Caml Light в основном поддержкой классического объектно-ориентированного
программирования. Также как и Standard ML строгий, но имеет некоторую встроенную поддержку
отложенных вычислений.

Miranda. Разработан Дэвидом Тернером, в качестве стандартного функционального языка,


использовавшего отложенные вычисления. Имеет строгую полиморфную систему типов. Как и ML
преподаётся во многих университетах. Оказал большое влияние на разработчиков языка Haskell.
Haskell. Один из самых распространённых нестрогих языков. Имеет очень развитую систему
типизации. Несколько хуже разработана система модулей. Последний стандарт языка - Haskell 98.
Gofer (GOod For Equational Reasoning). Упрощённый диалект Haskell’а. Предназначен для обучения
функциональному программированию.

Clean. Специально предназначен для параллельного и распределённого программирования. По


синтаксису напоминает Haskell. Чистый. Использует отложенные вычисления. С компилятором
поставляется набор библиотек (I/O libraries), позволяющих программировать графический
пользовательский интерфейс под Win32 или MacOS.

Шевченко Александр Сергеевич () Функциональное программирование 2 октября 2009 г. 11 / 42


Элементы функционального программирования Введение в функциональное программирование

Internet-ресурсы по функциональному программированию

www.haskell.org - очень насыщенный сайт, посвящённый функциональному программированию в


общем и языку Haskell в частности. Содержит различные справочные материалы, список
интерпретаторов и компиляторов Haskell’а (в настоящий момент все интерпретаторы и компиляторы
бесплатны). Кроме того, имеется обширный список интересных ссылок на ресурсы по теории
функционального программирования и другим языкам (Standard ML, Clean).

cm.bell-labs.com/cm/cs/what/smlnj - Standard ML of New Jersey. Очень хороший компилятор. В


бесплатный дистрибутив помимо компилятора входят утилиты MLYacc и MLLex и библиотека
Standard ML Basis Library. Отдельно можно взять документацию по компилятору и библиотеке.

www.harlequin.com/products/ads/ml/ - Harlequin MLWorks, коммерческий компилятор Standard ML.


Однако в некоммерческих целях можно бесплатно пользоваться версией с несколько ограниченными
возможностями.

caml.inria.fr - институт INRIA. Домашний сайт команды разработчиков языков Caml Light и Objective
Caml. Можно бесплатно скачать дистрибутив Objective Caml, содержащий интерпретатор,
компиляторы байт-кода и машинного кода, Yacc и Lex для Caml, отладчик и профайлер,
документацию, примеры. Качество компилированного кода у этого компилятора очень хорошее, по
скорости опережает даже Standard ML of New Jersey.

www.cs.kun.nl/ clean/ - содержит дистрибутив компилятора с языка Clean. Компилятор


коммерческий, но допускается бесплатное использование в некоммерческих целях. Из того, что
компилятор коммерческий, следует его качество (очень быстр), наличие среды разработчика,
хорошей документации и стандартной библиотеки.

Шевченко Александр Сергеевич () Функциональное программирование 2 октября 2009 г. 12 / 42


Элементы функционального программирования Введение в функциональное программирование

Список литературы

1 Хювёнен Э., Сеппенен И. Мир Lisp’а. В 2-х томах. М.: Мир, 1990.
2 Бердж В. Методы рекурсивного программирования. М.: Машиностроение, 1983.
3 Филд А., Харрисон П. Функциональное программирование. М.: Мир, 1993.
4 Хендерсон П. Функциональное программирование. Применение и реализация. М.: Мир,
1983.
5 Джонс С., Лестер Д. Реализация функциональных языков. М.: Мир, 1991.
6 Henson M. Elements of functional languages. Dept. of CS. University of Sassex, 1990.
7 Fokker J. Functional programming. Dept. of CS. Utrecht University, 1995.
8 Thompson S. Haskell: The Craft of Functional Programming. 2-nd edition, Addison-Wesley,
1999.
9 Bird R. Introduction to Functional Programming using Haskell. 2-nd edition, Prentice Hall
Press, 1998.

Шевченко Александр Сергеевич () Функциональное программирование 2 октября 2009 г. 13 / 42


Элементы функционального программирования Введение в язык Haskell

История языка Haskell

1 Начало 1930-х: Church, формализация функций в λ-исчислении


2 1960: John McCarthy, LISP – первый функциональный язык программирования
3 1978: John Backus, FP – система комбинаторного программирования
4 конец 1970-х: Edinburgh univ., ML – meta-language
5 1985-1986: David Turner, Miranda – функциональный язык с «ленивыми» вычислениями
6 1990: Ericsson, Erlang – «коммерческий» функциональный язык
7 1988: Paul Hudak, Haskell – первая версия языка Haskell
8 1999: Haskell group, Haskell’98 – «стандартная» версия языка Haskell
http://haskell.org/onlinereport/index.html - пересмотренное сообщение о языке Haskell’98
http://haskell.org/tutorial - введение в Haskell

Haskell – чисто функциональный язык программирования, названный в честь Хаскелла


Карри (Haskell B. Curry – 1900-1982), известного, главным образом, благодаря работам в
области математической логики и комбинаторной логики в конце 1950-х – начале 1960-х
годов

Шевченко Александр Сергеевич () Функциональное программирование 2 октября 2009 г. 14 / 42


Элементы функционального программирования Введение в язык Haskell

Типы данных и базовые конструкции языка Haskell

Элементарные типы данных


1 Integer, Int – целые значения (25, -17, 111222333444555666777888)
2 Float, Double – вещественные значения (3.14, -2.718281828459045)
3 Char – символьные значения (’A’, ’*’, ’3’)
4 Bool – логические значения (True, False)
Идентификаторы: fact, fAcToRiAl, fact_1, fact”
Знаки операций: +, -, *, <, ==
Идентификаторы применяются для обозначения констант – значений разных типов
(простых, составных, функций) и типов. Любому идентификатору можно сопоставить тип и
значение:

school : : Integer
s c h o o l = 366
p i H a l f : : Double
p i H a l f = 3.1415926536 / 2

Шевченко Александр Сергеевич () Функциональное программирование 2 октября 2009 г. 15 / 42


Элементы функционального программирования Введение в язык Haskell

Кортежи и функции

Значения могут объединяться в более сложные с помощью кортежирования.


Например:

p a i r : : ( Double , D o u b l e )
pair = (2.7 , 3.14)
a t t r i b u t e s : : ( Char , ( I n t , I n t , I n t ) , B o o l )
a t t r i b u t e s = ( ’M’ , ( 1 7 , 4 , 1 9 5 5 ) , True )

Тип функции определяется типами аргументов и результата, например:

s i n : : D o u b l e −> D o u b l e −− а р г у м е н т и р е з у л ь т а т типа D o u b l e
p l u s I n t : : I n t −> I n t −> I n t −− два а р г у м е н т а типа I n t , р е з у л ь т а т I n t
divMod : : ( I n t , I n t ) −> ( I n t , I n t ) −− а р г у м е н т и р е з у л ь т а т − кортежи

Выражения составляются из констант применением операций и функций, например:


r e s u l t = s i n (3.1416 / 4) − 2.5
c10 = 3 + p l u s I n t 3 4
p a i r = divMod ( 1 4 5 8 , p l u s I n t 176 1 9 2 )
Операции и функции отличаются только формой записи. Следующие выражения эквивалентны:

3 + 8 и (+) 3 8
27 ‘ d i v ‘ 4 и d i v 27 4
7 ‘ p l u s I n t ‘ 11 и p l u s I n t 7 11

Шевченко Александр Сергеевич () Функциональное программирование 2 октября 2009 г. 16 / 42


Элементы функционального программирования Введение в язык Haskell

Определение функций с помощью уравнений

Уравнения задают правила, по которым происходит вычисление функции, то есть каким


образом результат получается из аргументов функции, например:
p l u s I n t : : I n t −> I n t −> I n t
plusInt a b = a + b
divMod : : ( I n t , I n t ) −> ( I n t , I n t )
divMod ( a , b ) = ( a ‘ d i v ‘ b , a ‘ mod ‘ b )
Уравнения могут содержать условные выражения и рекурсивные обращения, например:
f a c t o r i a l : : I n t e g e r −> I n t e g e r
f a c t o r i a l n = i f n == 0 t h e n 1
e l s e n ∗ ( f a c t o r i a l ( n −1))
sum : : I n t e g e r −> I n t e g e r
sum n = n + i f n == 0 t h e n 0 e l s e sum ( n−1)
Уравнений для одной функции может быть несколько, тогда аргументы последовательно
сопоставляются с образцами:
factorial2 :: I n t e g e r −> I n t e g e r
factorial2 0 = 1
factorial2 n = n ∗ ( f a c t o r i a l 2 ( n −1))

Шевченко Александр Сергеевич () Функциональное программирование 2 октября 2009 г. 17 / 42


Элементы функционального программирования Введение в язык Haskell

Подготовка и запуск программ

Шевченко Александр Сергеевич () Функциональное программирование 2 октября 2009 г. 18 / 42


Элементы функционального программирования Введение в язык Haskell

Пример запуска программы на исполнение

Шевченко Александр Сергеевич () Функциональное программирование 2 октября 2009 г. 19 / 42


Элементы функционального программирования Введение в язык Haskell

Исполнение программ с помощью текстовой подстановки

f a c t o r i a l : : I n t e g e r −> I n t e g e r
f a c t o r i a l n | n == 0 = 1
| n > 0 = n ∗ ( f a c t o r i a l ( n −1))

factorial 3
3 ∗ ( f a c t o r i a l (3 −1))
3 ∗ ( f a c t o r i a l 2)
3 ∗ (2 ∗ ( f a c t o r i a l (2 −1)))
3 ∗ (2 ∗ ( f a c t o r i a l 1))
3 ∗ (2 ∗ (1 ∗ ( f a c t o r i a l (1 −1))))
3 ∗ (2 ∗ (1 ∗ ( f a c t o r i a l 0 ) ) )
3 ∗ (2 ∗ (1 ∗ 1))
6

Шевченко Александр Сергеевич () Функциональное программирование 2 октября 2009 г. 20 / 42


Элементы функционального программирования Введение в язык Haskell

Несколько определений простых арифметических функций

– Вычисление наибольшего общего делителя двух натуральных чисел


gcd : : I n t e g e r −> I n t e g e r −> I n t e g e r
gcd m n | m < n = gcd n m
| n < 0 = e r r o r " gcd : ␣Wrong␣ argument "
gcd m 0 = m
gcd m n = gcd n (m ‘ mod ‘ n )
– Проверка заданного натурального числа на простоту
prime : : I n t e g e r −> B o o l
p r i m e ’ ␣␣␣␣␣␣␣␣␣␣␣␣ : : ␣ I n t e g e r ␣−>␣ I n t e g e r ␣−>␣ Bool
prime ␣p␣␣␣␣ | ␣p␣<=␣0␣␣␣␣␣␣␣␣␣␣=␣␣ e r r o r ␣" prime : ␣Non−p o s i t i v e ␣ argument "
␣␣␣␣␣␣␣␣␣␣␣ | ␣ o t h e r w i s e ␣␣␣␣␣␣␣=␣␣ prime ’ 2 p
p r i m e ’ ␣d␣p␣ | ␣d␣∗␣d␣>␣p␣␣␣␣␣␣␣=␣␣True
␣␣␣␣␣␣␣␣␣␣␣ | ␣p␣ ‘mod ‘ ␣d␣==␣0␣␣=␣␣ F a l s e
␣␣␣␣␣␣␣␣␣␣␣ | ␣ o t h e r w i s e ␣␣␣␣␣␣␣=␣␣ prime ’ ( d+1) p

Шевченко Александр Сергеевич () Функциональное программирование 2 октября 2009 г. 21 / 42


Элементы функционального программирования Введение в язык Haskell

Эффективность рекурсивных функций.

f1 = f2 = 1
f n = f n −1 + f n −2 при n > 2
– Вычисление числа Фибоначчи, заданного порядковым номером
fib : : I n t e g e r −> I n t e g e r
fib 1 = 1
fib 2 = 1
fib n = f i b ( n−1) + f i b ( n−2)

fib 6
fib 5 + fib 4
( f i b 4 + f i b 3) + f i b 4
( ( f i b 3 + f i b 2) + f i b 3) + f i b 4
( ( ( f i b 2 + f i b 1) + f i b 2) + f i b 3) + f i b 4
( ( ( 1 + 1) + 1) + ( f i b 2 + f i b 1)) + f i b 4
(3 + 2) + ( f i b 3 + f i b 2)
(3 + 2) + ( ( f i b 2 + f i b 1) + 1)
(3 + 2) + ((1 + 1) + 1)
8

Шевченко Александр Сергеевич () Функциональное программирование 2 октября 2009 г. 22 / 42


Элементы функционального программирования Введение в язык Haskell

Эффективность рекурсивных функций. Концевая рекурсия.

fib : : I n t e g e r −> I n t e g e r
f i b ’ ␣ ␣ : : ␣ I n t e g e r ␣−>␣ I n t e g e r ␣−>␣ I n t e g e r ␣−>␣ I n t e g e r ␣−>␣ I n t e g e r
fib ’ n k f k f k 1 | k == n = f k
| k < n = f i b ’ ␣ n ␣ ( k +1) ␣ ( f k+f k 1 ) ␣ f k
f i b ␣ 1 ␣=␣ 1
f i b ␣ n ␣=␣ f i b ’ n 2 1 1

fib 6
fib ’ ␣6␣2␣1␣1
fib ’ 6 3 2 1
fib ’ ␣6␣4␣3␣2
fib ’ 6 5 5 3
fib ’ ␣6␣6␣8␣5
8

factorial : : I n t e g e r −> I n t e g e r
factorial 0 = 1
f a c t o r i a l n = n ∗ f a c t o r i a l ( n−1)

factorial : : I n t e g e r −> I n t e g e r
f a c t o r i a l ’ ␣ : : ␣ I n t e g e r ␣−>␣ I n t e g e r ␣−>␣ I n t e g e r
f a c t o r i a l ␣ n ␣=␣ f a c t o r i a l ’ n 1 −− ( f a c t o r i a l ’ ␣ n ␣ f ) ␣==␣ ( f ␣∗␣ n ! )
f a c t o r i a l ’ n f | n == 0 = f
| n > 0 = f a c t o r i a l ’ ␣ ( n −1)␣ ( n∗ f )

Шевченко Александр Сергеевич () Функциональное программирование 2 октября 2009 г. 23 / 42


Элементы функционального программирования Введение в язык Haskell

Списки в языке Haskell.


[] −− пустой список
[1 , 2 , 3] −− с п и с о к из заданых э л е м е н т о в
1:[2 , 3] −− присоединение головного элемента к списку
1:(2:(3:[])) −− с о з д а н и е с п и с к а с помощью к о н с т р у к т о р а ’ : ’
[1..n] −− с о з д а н и е с п и с к а с помощью арифметической п р о г р е с с и и
[2 , 4..20] −− арифметическая п р о г р е с с и я с заданной разностью

Типы списков
[ Integer ] −− список из целых чисел : [ 1 . . 1 0 ]
[ Char ] −− список из символов ( с т р о к а : " L i s t " == [ ’ L ’ , ’ i ’ , ’ s ’ , ’ t ’ ] )
[ ( Char , I n t ) ] −− список из кортежей : [ ( ’ L ’ , 1 ) , ( ’ i ’ , 2 ) , ( ’ s ’ , 3 ) ]
[[ Int ]] −− список из списков : [ [ 1 , 2 ] , [ 3 , 5 . . 1 0 ] , [ ] ]
Функция суммирования элементов списка

sumList :: [ I n t e g e r ] −> I n t e g e r
sumList [ ] = 0
sumList ( x : s ) = x + sumList s

sumList [1 , 3 , 6]
1 + sumList [3 , 6]
1 + 3 + sumList [ 6 ]
1 + 3 + 6 + sumList []
10

Шевченко Александр Сергеевич () Функциональное программирование 2 октября 2009 г. 24 / 42


Элементы функционального программирования Введение в язык Haskell

Еще один способ вычисления факториала.

factorial :: I n t e g e r −> I n t e g e r
p r o d L i s t ’ ␣ ␣ ␣ ␣ ␣ ␣ ␣ ␣ ␣ ␣ : : ␣ ␣ [ I n t e g e r ] ␣−>␣ I n t e g e r ␣−>␣ I n t e g e r
f a c t o r i a l ␣n␣ ␣ ␣ ␣ ␣ ␣ ␣ ␣ ␣=␣ ␣ p r o d L i s t ’ [ 1 . . n ] 1
p r o d L i s t ’ ␣ [ ] ␣p␣ ␣ ␣ ␣ ␣ ␣=␣ ␣p
p r o d L i s t ’ ( x : l s ) p = p r o d L i s t ’ ␣ l s ␣ ( p∗ x ) ␣ ␣ ␣ ␣ ␣−−␣ концевая ␣ р е к у р с и я
Несколько стандартных операций над списком и их определения.
1. Операция создания пары - prefix (x, y) = x : y = [x | y]. Эта операция также называется
конструктором или составителем.
2. Операция отсечения головы - head (x) = h (x). Это первая селективная операция.
3. Операция отсечения хвоста - tail (x) = t (x). Это вторая селективная операция.
head : : [ a ] −> a
head ( x : l s ) = x
head [ ] = e r r o r " head : ␣ empty ␣ l i s t "

tail :: [ a ] −> [ a ]
tail (x : ls ) = ls
tail [] = e r r o r " t a i l : ␣ empty ␣ l i s t "

length : : [ a ] −> I n t
length (x : l s ) = 1 + length ls
length [ ] = 0

null : : [ a ] −> B o o l
null (x : ls ) = False
null [] = True

Шевченко Александр Сергеевич () Функциональное программирование 2 октября 2009 г. 25 / 42


Элементы функционального программирования Введение в язык Haskell

Более сложные функции обработки списков.


last : : [ a ] −> a
last [] = e r r o r " l a s t : ␣ empty ␣ l i s t "
last [x] = x
last (x : ls ) = last ls

init : : [ a ] −> [ a ]
init [] = e r r o r " i n i t : ␣ empty ␣ l i s t "
init [x] = []
init (x : ls ) = x : init ls

(!!) : : [ a ] −> I n t −> a


[] !! _ = e r r o r " ( ! ! ) : ␣ empty ␣ l i s t "
(x : ls ) !! 0 = x
(x : ls ) !! n = l s ! ! ( n−1)

(++) : : [ a ] −> [ a ] −> [ a ]


[ ] ++ l s = ls
( x : l 1 ) ++ l 2 = x : ( l 1 ++ l 2 )

reverse : : [ a ] −> [ a ]
r e v e r s e ’ ␣ ␣ ␣ ␣ ␣ ␣ : : ␣ [ a ] ␣−>␣ [ a ] ␣−>␣ [ a ]
r e v e r s e ␣ l s ␣ ␣ ␣ ␣ ␣ ␣ ␣ ␣ ␣=␣ r e v e r s e ’ l s [ ]
r e v e r s e ’ ␣ [ ] ␣ l ␣ ␣ ␣ ␣ ␣ ␣=␣ l
reverse ’ (x : l s ) l = reverse ’␣ ls ␣(x : l )

Шевченко Александр Сергеевич () Функциональное программирование 2 октября 2009 г. 26 / 42


Элементы функционального программирования Определение новых типов данных

Шевченко Александр Сергеевич () Функциональное программирование 2 октября 2009 г. 27 / 42


Элементы функционального программирования Определение новых типов данных

Определение синонимов для типов


type String = [ Char ]
t y p e Coord = ( Double , D o u b l e )
type Pair a = (a , a)
t y p e Complex = P a i r D o u b l e

Использование синонимов
find : : S t r i n g −> Char −> I n t
find [] _ = −1
f i n d ( x : s ) y | x == y = 0
| otherwise = 1 + find s y

distance : : Coord −> Coord −> D o u b l e


d i s t a n c e ( x1 , y1 ) ( x2 , y2 ) = s q r t ( ( x2−x1 ) ∗ ( x2−x1 ) + ( y2−y1 ) ∗ ( y2−y

complexAdd : : Complex −> Complex −> Complex


complexAdd ( r1 , i 1 ) ( r2 , i 2 ) = ( r 1+r2 , i 1+i 2 )

swap : : P a i r a −> P a i r a
swap ( x , y ) = ( y , x )

Шевченко Александр Сергеевич () Функциональное программирование 2 октября 2009 г. 27 / 42


Элементы функционального программирования Определение новых типов данных

Определение конструкторов

d a t a WeekDay = Sun | Mon | Tue | Wed | Thu | Fri | Sat


data Bool = F a l s e | True
Использование конструкторов

weekend : : WeekDay −> B o o l


weekend Sun = True
weekend S a t = True
weekend _ = False

Конструкторы с параметром

d a t a Coord = P o i n t Double Double


data Pair a = Couple a a

d a t a Coord = Coord D o u b l e D o u b l e
data Pair a = Pair a a

Использование конструкторов с параметрами

distance : : Coord −> Coord −> D o u b l e


d i s t a n c e ( P o i n t x1 y1 ) ( P o i n t x2 y2 ) =
s q r t ( ( x2−x1 ) ∗ ( x2−x1 ) + ( y2−y1 ) ∗ ( y2−y1 ) )

distance : : Coord −> Coord −> D o u b l e


d i s t a n c e ( Coord x1 y1 ) ( Coord x2 y2 ) =
s q r t ( ( x2−x1 ) ∗ ( x2−x1 ) + ( y2−y1 ) ∗ ( y2−y1 ) )

swap :: Pair a -> Pair a swap (Couple x y) = Couple


swap :: Pair a -> Pair a swap (Pair x y) = Pair y x
yx
Шевченко Александр Сергеевич () Функциональное программирование 2 октября 2009 г. 28 / 42
Элементы функционального программирования Определение новых типов данных

Сложные типы данных.

data IntList = Nil | Cons I n t e g e r IntList


Сортировка списка.

insert : : ( Ord a ) => a −> [ a ] −> [ a ]


i n s e r t elem [ ] = [ elem ]
i n s e r t elem l i s t @ ( x : s ) | elem < x = elem : l i s t
| o t h e r w i s e = x : ( i n s e r t elem s )

bubble : : ( Ord a ) => [ a ] −> [ a ]


bubble [ ] = []
bubble ( x : s ) = i n s e r t x ( bubble s )

Шевченко Александр Сергеевич () Функциональное программирование 2 октября 2009 г. 29 / 42


Элементы функционального программирования Определение новых типов данных

Определение и обработка двоичного дерева.


d a t a T r e e a = Empty |
Node ( T r e e a ) a ( T r e e a )

myTree :: T r e e Char
myTree = Node ( Node
( Node Empty ’D ’ Empty )
’B ’
Empty )
’A ’
( Node
( Node Empty ’E ’ Empty )
’C ’
( Node Empty ’ F ’ Empty ) )

height :: T r e e a −> I n t
h e i g h t Empty = 0
h e i g h t ( Node t 1 _ t 2 ) = 1 + max ( h e i g h t t 1 ) ( h e i g h t t 2 )

Шевченко Александр Сергеевич () Функциональное программирование 2 октября 2009 г. 30 / 42


Элементы функционального программирования Определение новых типов данных

Сортировка с помощью двоичного дерева.

sort :: ( Ord a ) => [ a ] −> [ a ]


build :: ( Ord a ) => [ a ] −> T r e e a
flatten :: T r e e a −> [ a ]

sort ls = flatten ( build ls )

Шевченко Александр Сергеевич () Функциональное программирование 2 октября 2009 г. 31 / 42


Элементы функционального программирования Определение новых типов данных

Программа сортировки с помощью двоичного дерева.


d a t a T r e e a = Empty |
Node ( T r e e a ) a ( T r e e a )
sort : : ( Ord a ) => [ a ] −> [ a ]
build : : ( Ord a ) => [ a ] −> T r e e a
insert : : ( Ord a ) => a −> T r e e a −> T r e e a
f l a t t e n : : T r e e a −> [ a ]

sort ls = flatten ( build ls )

build [] = Empty
build (e : ls ) = insert e ( build ls )

i n s e r t e Empty = Node Empty e Empty


i n s e r t e ( Node t 1 n t 2 ) | e < n = Node ( i n s e r t e t 1 ) n t 2
| e >= n = Node t 1 n ( i n s e r t e t 2 )
f l a t t e n Empty = [ ]
f l a t t e n ( Node t 1 n t 2 ) = ( f l a t t e n t 1 ) ++ ( n : ( f l a t t e n t 2 ) )

Шевченко Александр Сергеевич () Функциональное программирование 2 октября 2009 г. 32 / 42


Средства функционального программирования Функции высших порядков

Функции высших порядков

sqr :: I n t e g e r −> I n t e g e r
sqr x = x ∗ x

source = [1 , 2 , 5, 7, 11]
sqr
dest = [ 1 , 4 , 25 , 49 , 121]
dest = map s q r s o u r c e

%map :: ( a −> b ) −> [ a ] −> [ b ] −− Альтернативная з а п и с ь


map :: ( I n t e g e r −> I n t e g e r ) −> [ I n t e g e r ] −> [ I n t e g e r ]

map _ [ ] = []
map f ( x : l s ) = ( f x ) : ( map f l s )

Шевченко Александр Сергеевич () Функциональное программирование 2 октября 2009 г. 33 / 42


Средства функционального программирования Функции высших порядков

Функции высших порядков

Определение функций с помощью λ-выражений


λ-исчисление Черча - исчисление безымянных функций
s q r : $ \ lambda$x . ∗ x x
s q r = \ x −> ( x ∗ x )

Шевченко Александр Сергеевич () Функциональное программирование 2 октября 2009 г. 34 / 42


Средства функционального программирования Функции высших порядков

Функции высших порядков

Более сложная функция, заданная с помощью λ-выражения


f a c t o r i a l : : I n t e g e r −> I n t e g e r
f a c t o r i a l = \n −> c a s e n o f
0 −> 1
n −> n ∗ f a c t o r i a l ( n−1)

Конструкция case - общая форма задания выбора по образцу


case expr of
p a t t 1 | cond11 −> e x p r 1 1
| cond12 −> e x p r 1 2 ...
p a t t 2 | cond21 −> e x p r 2 1
| cond22 −> e x p r 2 2 ...
...

Шевченко Александр Сергеевич () Функциональное программирование 2 октября 2009 г. 35 / 42


Средства функционального программирования Функции высших порядков

Функции высших порядков

Еще один пример функции высшего порядка


source = [1 ,2 ,5 ,7 ,11]
f u n c = (+)
seed = 0

1+2+5+7+11+0=26

func = ( : )
seed = [ ]

1 : (2 : (5 : (7 : (11 : [])))) = [1 , 2 , 5 , 7 , 11]

foldr :: ( a −> b −> b ) −> b −> [ a ] −> b


f o l d r func seed [ ] = seed
f o l d r func seed ( x : l s ) = func x ( f o l d r func seed l s )

Шевченко Александр Сергеевич () Функциональное программирование 2 октября 2009 г. 36 / 42


Средства функционального программирования Функции высших порядков

Функции высших порядков

С помощью функций высшего порядка можно программировать


factorial :: I n t e g e r −> I n t e g e r
factorial n = f o l d r (∗) 1 [ 1 . . n ]

search :: ( Eq a ) => a −> [ a ] −> B o o l


search e l i s t = f o l d r ( | | ) F a l s e ( map ( \ x −> x == e ) list )

search 5 [1 , 2 , 5 , 7 , 11]
foldr ( | | ) F a l s e ( map ( \ x −> x == 5 ) [ 1 , 2 , 5 , 7 , 1 1 ] )
foldr ( | | ) F a l s e [ F a l s e , F a l s e , True , F a l s e , F a l s e ]
False | | ( F a l s e | | ( True | | ( F a l s e | | ( F a l s e | | F a l s e ) ) ) )
True

join1 :: [ a ] −> [ a ] −> [ a ]


join1 [] l i s t = list
join1 (x : ls ) l i s t = x : ( join1 ls l i s t )

join2 :: [ a ] −> [ a ] −> [ a ]


join2 lis1 lis2 = foldr (:) lis2 lis1

Шевченко Александр Сергеевич () Функциональное программирование 2 октября 2009 г. 37 / 42


Средства функционального программирования Функции высших порядков

Функции высших порядков

Еще несколько полезных функций высших порядков.

−− " левая ␣ в с т а в к а " − еще один с п о с о б с в е р т к и с п и с к а


foldl :: ( b −> a −> b ) −> b −> [ a ] −> b
f o l d l _ seed [ ] = seed
f o l d l f seed ( x : l s ) = f o l d l f ( f seed x ) l s

reverse :: [ a ] −> [ a ]
reverse list = f o l d l app [ ] l i s t
w h e r e app l x = x: l

flip :: ( a −> b −> c ) −> ( b −> a −> c )


flip f = f l i p ’ ␣ where ␣ f l i p ’ x y = f y x

reverse :: [ a ] −> [ a ]
reverse list = foldl ( flip (:)) [] list

−− Альтернативный в а р и а н т
comp :: ( b −> c ) −> ( a −> b ) −> ( a −> c )
(.) :: ( b −> c ) −> ( a −> b ) −> ( a −> c )
comp f g = f g where f g x = f ( g x )
f . g = f g where f g x = f ( g x )
sqr :: (Num a ) => a −> a
sqr :: (Num a ) => a −> a
sqr a = a ∗ a
sqr a = a ∗ a
power4 :: (Num a ) => a −> a
power4 :: (Num a ) => a −> a
power4 = comp s q r s q r
power4 = sqr . sqr

Шевченко Александр Сергеевич () Функциональное программирование 2 октября 2009 г. 38 / 42


Средства функционального программирования Функции высших порядков

Функции высших порядков

Свертки сложных структур данных.

d a t a T r e e a = Empty |
Node ( T r e e a ) a ( T r e e a )

Правосторонний обход этого дерева: F, C, E, A, B, D


Функция, осуществляющая свертку в порядке
правостороннего обхода:

f o l d T r e e (++) s e e d t 1 =>
D ++ (B ++ (A ++ ( E ++ (C ++ ( F ++ s e e d ) ) ) ) )

foldTree :: ( a −> b −> b ) −> b −> T r e e a −> b


f o l d T r e e _ s e e d Empty = seed
f o l d T r e e f s e e d ( Node t 1 n t 2 ) = f o l d T r e e f ( f n ( f o l d T r e e f s e e d t 2 ) ) t 1

" Разглаживание " д е р е в а с помощью f o l d T r e e :


flatten :: T r e e a −> [ a ]
flatten t = foldTree (:) [ ] t

Шевченко Александр Сергеевич () Функциональное программирование 2 октября 2009 г. 39 / 42


Средства функционального программирования Функции высших порядков

Функции высших порядков


Сортировка с помощью дерева: используем функции высших порядков.

d a t a T r e e a = Empty |
Node ( T r e e a ) a ( T r e e a )
sort : : ( Ord a ) => [ a ] −> [ a ]
build : : ( Ord a ) => [ a ] −> T r e e a
insert : : ( Ord a ) => a −> T r e e a −> T r e e a
f l a t t e n : : T r e e a −> [ a ]
sort ls = flatten ( build ls )
i n s e r t e Empty = Node Empty e Empty
i n s e r t e ( Node t 1 n t 2 ) | e < n = Node ( i n s e r t e t1 ) n t2
| e >= n = Node t1 n ( i n s e r t e t2 )

build [] = Empty
build (e : ls ) = insert e ( build ls )
f l a t t e n Empty = []
f l a t t e n ( Node t1 n t 2 ) = ( f l a t t e n t 1 ) ++ ( n : ( f l a t t e n t 2 ) )

−− Альтернативный в а р и а н т
foldTree :: ( a −> b −> b ) −> b −> T r e e a −> b
f o l d T r e e _ s e e d Empty = seed
f o l d T r e e f s e e d ( Node t 1 n t 2 ) = f o l d T r e e f ( f n ( f o l d T r e e f s e e d t 2 ) ) t 1

build list = foldr i n s e r t Empty l i s t

flatten tree = foldTree (:) [] tree

Шевченко Александр Сергеевич () Функциональное программирование 2 октября 2009 г. 40 / 42

Вам также может понравиться