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

15
Сошников Дмитрий Валерьевич к.ф.-м.н., доцент [email protected] Факультет инноваций и высоких технологий Московский физико-технический институт

Upload: illana-lindsay

Post on 03-Jan-2016

85 views

Category:

Documents


1 download

DESCRIPTION

Функциональное программирование. Факультет инноваций и высоких технологий Московский физико-технический институт. Лекция 10. Хвостовая рекурсия. Порядковое представление списков и матриц. Хвостовая рекурсия. - PowerPoint PPT Presentation

TRANSCRIPT

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

Сошников Дмитрий Валерьевич

к.ф.-м.н., доцент[email protected]

Факультет инноваций и высоких технологий

Московский физико-технический институт

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

Лекция 10

Хвостовая рекурсия. Порядковое представление списков и матриц.

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

3

©20

08 С

ошни

ков

Д.В

.

Во многих случаях (особенно при обработке списков) рекурсивные алгоритмы могут быть сведены к итерационным

Такая рекурсия называется хвостовой Линейная Рекурсивный вызов – в конце тела функции

▪ т.е. вызов совершается сразу после выполнения тела функции

Не выделяется промежуточная память

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

4

©20

08 С

ошни

ков

Д.В

.

После рекурсивного вызова выполняется операция сложения

При каждом погружении выделяется память на промежуточные вычисления и на адрес возврата – O(n)

В случае итерационного алгоритма выделение памяти бы не потребовалось

let rec length = function [] -> 0 | _::t -> 1+length(t);;

length [a;b;c]

length [b;c]

length [c]

length []

0

1+0=1

1+1=2

1+2=3

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

5

©20

08 С

ошни

ков

Д.В

.

Вводим промежуточную функцию len : int → T list → int

При каждом откусывании головы числовой параметр (разностный счетчик) увеличивается, затем делается рекурсивный вызов

В конце значение счетчика возвращается как результат

let length L = let rec len a = function [] -> a | _::t -> len (a+1) t in len 0 L;;

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

6

©20

08 С

ошни

ков

Д.В

.

Сложение выполняется перед рекурсивным вызовом Результат возвращается напрямую в вызывающую

функцию => не требуется выделения памяти Требуемая память – O(1)

let rec len a = function [] -> a | _::t -> len (a+1) t

len 0 [a;b;c]

len 1 [b;c]

len 2 [c]

len 3 []

3

3

3

3

3

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

7

©20

08 С

ошни

ков

Д.В

.

rev: T list → T listrev: T list → T list

let rec rev = function [] -> []| h::t -> (rev t)@[h];;

• Не хвостовая рекурсия• Сложность: O(n2), поскольку append имеет линейную

сложность

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

©20

08 С

ошни

ков

Д.В

.

8

Вводим аналог счетчика – списковый Начиная с [ ], каждое откусывание головы

присоединяется к этому списку

let rev L = let rec rv s = function [] -> s | h::t -> rv (h::s) t in rv [] L;;

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

©20

08 С

ошни

ков

Д.В

.

9

Возможно предложить другое, более «функциональное» определения списка как последовательности чисел

list : int -> A

type 'a nlist = int->'a option ;;

let nhd l = l 0;;let ntl l = fun x -> if x>=0 then l (x+1) else None;;let nempty l = (l 0) = None;;let mempty = fun _ -> None;;let ncons a l = fun x ->

(if x=0 then Some(a) else l(x-1));;

• Возможно работать с таким списком привычным образом, определив основные операции

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

©20

08 С

ошни

ков

Д.В

.

10

Другие примеры – на семинаре и в рамках лабораторной работы №1

Порядковое представление неэффективно (представление функции в памяти), но любопытно с теоретической точки зрения

Может использоваться для представления матриц (в особенности разреженных)

let rec to_list l = if nempty l then [] else (nhd l)::to_list (ntl l)

let rec map f l = match nhd l with None -> mempty | Some(x) -> ncons (f x) (map f (ntl l));;

let rec from_list = function [] -> mempty| h::t -> ncons h (from_list t)

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

©20

08 С

ошни

ков

Д.В

.

11

Удобно для разреженных матриц, при этом надо отдельно хранить размерность:▪ type ‘a rmatrix = int*int*(int->int->’a option);;

Когда использовать то или иное представление?

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

12

©20

08 С

ошни

ков

Д.В

.

Списковое транспонирование оказывается менее очевидной операцией, чем определение aij=bji

А соответственно и другие операции, использующие столбцы (умножение), будут сложнее (хотя могут быть сведены к транспонированию)

let rec slice = function [] -> ([],[])| h::t -> let (u,v) = slice t in (hd h::u, tl h::v);;

[[1 2 3] [[1 4 7] [4 5 6] [2 5 8] [7 8 9]] [3 6 9]]

let rec trans = function []::_ -> [] | x -> let (h,r) = slice x in h::(trans r);;

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

13

©20

08 С

ошни

ков

Д.В

.

Мораль: Для различных задач оказываются

удобными различные представления абстрактных типов данных

let transp (n,m) = (n, fun i j -> m j i);;

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

14

©20

08 С

ошни

ков

Д.В

.

Matrix<T>, Vector<T>, RowVector<T>matrix = Matrix<float>, rowvec, vector

#r "FSharp.PowerPack.dll"open Microsoft.FSharp.Core;;open Microsoft.FSharp.Math;;let M = Matrix.of_list [[1.0;2.0;3.0];[4.0;5.0;6.0];[7.0;8.0;9.0]];;M.Transpose;;M.Row(1);;(Vector.of_list [1.0;2.0;3.0]) *

(RowVector.of_list [1.0;2.0;3.0]);;M*M.Transpose;;

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

15

©20

08 С

ошни

ков

Д.В

.

Операция Список Массив со случайным доступом

Случайный доступ O(n) O(1)

Поиск O(n) O(n)

Вставка элемента в начало / удаление первого элемента

O(1) O(n)

Вставка / удаление элемента в конец (середину)

O(n) O(n)

Реверсирование O(n) [O(n2)] O(n)