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

21
1 Эффективность рекурсивных функций. Кубенский А.А. Функциональное программирование. Глава 1. Элементы функционального программирования. -- Вычисление числа Фибоначчи, заданного порядковым номером fib :: Integer -> Integer fib 1 = 1 fib 2 = 1 fib n = fib (n-1) + fib (n-2) fib 6 fib 5 + fib 4 (fib 4 + fib 3) + fib 4 ((fib 3 + fib 2) + fib 3) + fib 4 (((fib 2 + fib 1) + fib 2) + fib 3) + fib 4 (((1 + 1) + 1) + (fib 2 + fib 1)) + fib 4 (3 + 2) + (fib 3 + fib 2) (3 + 2) + ((fib 2 + fib 1) + 1) (3 + 2) + ((1 + 1) + 1) 8 f 1 = f 2 = 1 f n = f n-1 + f n-2 при n > 2

Upload: aspen

Post on 20-Mar-2016

87 views

Category:

Documents


1 download

DESCRIPTION

Эффективность рекурсивных функций. f 1 = f 2 = 1 f n = f n-1 + f n-2 при n > 2. -- Вычисление числа Фибоначчи, заданного порядковым номером fib :: Integer -> Integer fib 1 = 1 fib 2 = 1 fib n = fib (n-1) + fib (n-2). fib 6 fib 5 + fib 4 (fib 4 + fib 3) + fib 4 - PowerPoint PPT Presentation

TRANSCRIPT

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

1

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

Кубенский А.А. Функциональное программирование.Глава 1. Элементы функционального программирования.

-- Вычисление числа Фибоначчи, заданного порядковым номеромfib :: Integer -> Integerfib 1 = 1fib 2 = 1fib n = fib (n-1) + fib (n-2)

fib 6fib 5 + fib 4(fib 4 + fib 3) + fib 4((fib 3 + fib 2) + fib 3) + fib 4(((fib 2 + fib 1) + fib 2) + fib 3) + fib 4(((1 + 1) + 1) + (fib 2 + fib 1)) + fib 4(3 + 2) + (fib 3 + fib 2)(3 + 2) + ((fib 2 + fib 1) + 1)(3 + 2) + ((1 + 1) + 1)8

f1 = f2 = 1

fn = fn-1 + fn-2 при n > 2

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

2

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

Кубенский А.А. Функциональное программирование.Глава 1. Элементы функционального программирования.

fib :: Integer -> Integerfib' :: Integer -> Integer -> Integer -> Integer -> Integerfib' n k fk fk1 | k == n = fk | k < n = fib' n (k+1) (fk+fk1) fk fib 1 = 1fib n = fib' n 2 1 1

fib 6fib' 6 2 1 1fib' 6 3 2 1fib' 6 4 3 2fib' 6 5 5 3fib' 6 6 8 58

factorial :: Integer -> Integerfactorial 0 = 1factorial n = n * factorial (n-1)

factorial :: Integer -> Integerfactorial' :: Integer -> Integer -> Integerfactorial n = factorial' n 1 -- (factorial' n f) == (f * n!)factorial' n f | n == 0 = f | n > 0 = factorial' (n-1) (n*f)

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

3

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

Кубенский А.А. Функциональное программирование.Глава 1. Элементы функционального программирования.

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

Типы списков

[Char] -- список из символов (строка: "List" == ['L','i','s','t'])[(Char, Int)] -- список из кортежей: [('L', 1), ('i', 2), ('s', 3)][[Int]] -- список из списков: [[1, 2], [3, 5..10], []]

[Integer] -- список из целых чисел: [1..10]

Функция суммирования элементов спискаsumList :: [Integer] -> IntegersumList [] = 0sumList (x:s) = x + sumList s

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

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

4

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

Кубенский А.А. Функциональное программирование.Глава 1. Элементы функционального программирования.

factorial :: Integer -> Integerfactorial n = product [1..n]

Несколько стандартных операций над списком и их определения.

head :: [a] -> ahead (x:ls) = xhead [] = error "head: empty list"

tail :: [a] -> [a]tail (x:ls) = lstail [] = error "tail: empty list"

length :: [a] -> Intlength (x:ls) = 1 + length lslength [] = 0

null :: [a] -> Boolnull (x:ls) = Falsenull [] = True

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

5

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

Кубенский А.А. Функциональное программирование.Глава 1. Элементы функционального программирования.

last :: [a] -> alast [] = error "last: empty list"last [x] = xlast (x:ls) = last ls

init :: [a] -> [a]init [] = error "init: empty list"init [x] = []init (x:ls) = x : init ls

(!!) :: [a] -> Int -> a[] !! _ = error "(!!): empty list"(x:ls) !! 0 = x(x:ls) !! n = ls !! (n-1)

(++) :: [a] -> [a] -> [a][] ++ ls = ls(x:l1) ++ l2 = x : (l1 ++ l2)

reverse :: [a] -> [a] reverse' :: [a] -> [a] -> [a] reverse ls = reverse' ls []reverse' [] l = lreverse' (x:ls) l = reverse' ls (x:l)

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

6

Еще некоторые стандартные функции обработки списков.

Кубенский А.А. Функциональное программирование.Глава 1. Элементы функционального программирования.

sum :: Num a => [a] -> asum [] = 0sum (x:t) = x + sum t

take :: Int -> [a] -> [a]take _ [] = []take n _ | n <= 0 = []take n (x:t) = x : take (n – 1) t

maximum :: Ord a => [a] -> amaximum [] = error “maximum: empty list"maximum [x] = xmaximum (x:t) = max x (maximum t)

zip :: [a] -> [b] -> [(a, b)]zip [] _ = []zip _ [] = []zip (e1:t1) (e2:t2) = (e1, e2) : zip t1 t2

unzip :: [(a,b)] -> ([a],[b]) unzip [] = ([], [])unzip ((e1,e2):t) = (e1:tail1, e2:tail2) where (tail1,tail2) = unzip t

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

7

1.3. Определение новых типов данных.

Кубенский А.А. Функциональное программирование.Глава 1. Элементы функционального программирования.

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

type String = [Char]type Coord = (Double, Double)type Pair a = (a, a)type Complex = Pair Double

Использование синонимовfind :: String -> Char -> Intfind [] _ = -1find (x:s) y | x == y = 0 | otherwise = 1 + find s y

distance :: Coord -> Coord -> Doubledistance (x1, y1) (x2, y2) = sqrt ((x2-x1) * (x2-x1) + (y2-y1) * (y2-y1))

complexAdd :: Complex -> Complex -> ComplexcomplexAdd (r1, i1) (r2, i2) = (r1+r2, i1+i2)

swap :: Pair a -> Pair aswap (x, y) = (y, x)

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

8

1.3. Определение новых типов данных.

Кубенский А.А. Функциональное программирование.Глава 1. Элементы функционального программирования.

Определение конструкторовdata WeekDay = Sun | Mon | Tue | Wed | Thu | Fri | Satdata Bool = False | True

Использование конструкторовweekend :: WeekDay -> Boolweekend Sun = Trueweekend Sat = Trueweekend _ = False

Конструкторы с параметромdata Coord = Point Double Doubledata Pair a = Couple a a

Использование конструкторов с параметрамиdistance :: Coord -> Coord -> Doubledistance (Point x1 y1) (Point x2 y2) = sqrt ((x2-x1) * (x2-x1) + (y2-y1) * (y2-y1))

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

data Coord = Coord Double Doubledata Pair a = Pair a a

distance :: Coord -> Coord -> Doubledistance (Coord x1 y1) (Coord x2 y2) = sqrt ((x2-x1) * (x2-x1) + (y2-y1) * (y2-y1))

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

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

9Кубенский А.А. Функциональное программирование.Глава 1. Элементы функционального программирования.

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

data IntList = Nil | Cons Integer IntListsumList :: IntList -> IntegersumList Nil = 0sumList (Cons e ls) = e + sumList ls

data List a = Nil | a :+: (List a)sumList :: List Integer -> IntegersumList Nil = 0sumList (e :+: ls) = e + sumList ls

sumList :: (Num a) => List a -> asumList Nil = 0sumList (e :+: ls) = e + sumList ls

data [a] = [] | a : [a]sumList :: (Num a) => [a] -> asumList [] = 0sumList (e : ls) = e + sumList ls

Сортировка списка.insert :: (Ord a) => a -> [a] -> [a]insert elem [] = [elem]insert elem list@(x:s) | elem < x = elem:list | otherwise = x:(insert elem s)

bubble :: (Ord a) => [a] -> [a]bubble [] = []bubble (x:s) = insert x (bubble s)

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

10

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

Кубенский А.А. Функциональное программирование.Глава 1. Элементы функционального программирования.

data Tree a = Empty | Node (Tree a) a (Tree a)A

B C

D E F

myTree :: Tree CharmyTree = Node (Node (Node Empty 'D' Empty) 'B' Empty) 'A' (Node (Node Empty 'E' Empty) 'C' (Node Empty 'F' Empty))

height :: Tree a -> Intheight Empty = 0height (Node t1 _ t2) = 1 + max (height t1) (height t2)

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

11Кубенский А.А. Функциональное программирование.Глава 1. Элементы функционального программирования.

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

9

2

6

1

8

4

92 6

1

4

8

1

2

4

6

8

9

build flatten

sort :: (Ord a) => [a] -> [a]build :: (Ord a) => [a] -> Tree aflatten :: Tree a -> [a]

sort ls = flatten (build ls)

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

12Кубенский А.А. Функциональное программирование.Глава 1. Элементы функционального программирования.

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

data Tree a = Empty | Node (Tree a) a (Tree a)sort :: (Ord a) => [a] -> [a]build :: (Ord a) => [a] -> Tree ainsert :: (Ord a) => a -> Tree a -> Tree aflatten :: Tree a -> [a]sort ls = flatten (build ls)build [] = Emptybuild (e:ls) = insert e (build ls)insert e Empty = Node Empty e Emptyinsert e (Node t1 n t2) | e < n = Node (insert e t1) n t2 | e >= n = Node t1 n (insert e t2)flatten Empty = []flatten (Node t1 n t2) = (flatten t1) ++ (n : (flatten t2))

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

13

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

Кубенский А.А. Функциональное программирование.Глава 2. Средства функционального программирования.

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

sqr :: Integer -> Integersqr x = x * x

source = [1, 2, 5, 7, 11]

dest = [1, 4, 25, 49, 121]sqr

dest = map sqr source

map :: (Integer -> Integer) -> [Integer] -> [Integer]

map _ [] = []map f (x:ls) = (f x) : (map f ls)

map :: (a -> b) -> [a] -> [b]

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

14Кубенский А.А. Функциональное программирование.Глава 2. Средства функционального программирования.

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

λ-исчисление Черча – исчисление безымянных функций

sqr : λx.* x x

sqr = \x -> (x * x)

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

15Кубенский А.А. Функциональное программирование.Глава 2. Средства функционального программирования.

Более сложная функция, заданная с помощью λ-выраженияfactorial :: Integer -> Integerfactorial = \n -> case n of 0 -> 1 n -> n * factorial (n-1)

Конструкция case – общая форма задания выбора по образцуcase expr of patt1 | cond11 -> expr11

| cond12 -> expr12 ... patt2 | cond21 -> expr21

| cond22 -> expr22 ... ...

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

16Кубенский А.А. Функциональное программирование.Глава 2. Средства функционального программирования.

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

source = [ ] 0117521 , func = seed = +

+ +

(+) 0,

+

,

+

,

+ = 1118232526

func = (:) seed = []

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

foldr :: (a -> b -> b) -> b -> [a] -> bfoldr func seed [] = seed foldr func seed (x:ls) = func x (foldr func seed ls)

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

17Кубенский А.А. Функциональное программирование.Глава 2. Средства функционального программирования.

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

factorial :: Integer -> Integerfactorial n = foldr (*) 1 [1..n]

search :: (Eq a) => a -> [a] -> Boolsearch e list = foldr (||) False (map (\x -> x == e) list)

search 5 [1, 2, 5, 7, 11]foldr (||) False (map (\x -> x == 5) [1, 2, 5, 7, 11])foldr (||) False [False, False, True, False, False]False || (False || (True || (False || (False || False))))

join1 :: [a] -> [a] -> [a]join1 [] list = listjoin1 (x:ls) list = x : (join1 ls list)

join2 :: [a] -> [a] -> [a]join2 lis1 lis2 = foldr (:) lis2 lis1

True

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

18Кубенский А.А. Функциональное программирование.Глава 2. Средства функционального программирования.

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

-- "левая вставка" – еще один способ свертки спискаfoldl :: (b -> a -> b) -> b -> [a] -> bfoldl _ seed [] = seedfoldl f seed (x:ls) = foldl f (f seed x) ls

reverse :: [a] -> [a]reverse list = foldl app [] list where app l x = x:l

flip :: (a -> b -> c) -> (b -> a -> c)flip f = f' where f' x y = f y x

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

:: (b -> c) -> (a -> b) -> (a -> c) = fg where fg x = f (g x)

sqr :: (Num a) => a -> asqr a = a * apower4 :: (Num a) => a -> apower4 = comp sqr sqrsqr . sqr

compcomp f g(.)f . g

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

19Кубенский А.А. Функциональное программирование.Глава 2. Средства функционального программирования.

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

-- свертки без "зерна"foldl1, foldr1 :: (a -> a -> a) -> [a] -> afoldl1 _ [x] = xfoldl1 f (x:ls) = foldl f x lsfoldr1 _ [x] = xfoldr1 f (x:ls) = f x (foldr1 f ls)

all, any :: (a -> Bool) -> Boolall f list = foldr (&&) True (map f list)any f list = foldr (||) False (map f list)

takeWhile :: (a -> Bool) -> [a] -> [a]takeWhile _ [] = []takeWhile f (x:ls) | f x = x : takeWhile f ls | otherwise = []

zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]zipWith _ [] _ = []zipWith _ _ [] = []zipWith f (e1:t1) (e2:t2) = (f e1 e2) : zipWith f t1 t2-- кстати, zip list1 list2 = zipWith (,) list1 list2

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

20Кубенский А.А. Функциональное программирование.Глава 2. Средства функционального программирования.

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

data Tree a = Empty | Node (Tree a) a (Tree a)

A

B C

D E F

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

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

foldTree :: (a -> b -> b) -> b -> Tree a -> bfoldTree _ seed Empty = seedfoldTree f seed (Node t1 n t2) = foldTree f (f n (foldTree f seed t2)) t1

t1 =

foldTree (++) seed t1 => D ++ (B ++ (A ++ (E ++ (C ++ (F ++ seed)))))

«Разглаживание» дерева с помощью foldTree:flatten :: Tree a -> [a]flatten t = foldTree (:) [] t

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

21Кубенский А.А. Функциональное программирование.Глава 2. Средства функционального программирования.

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

build [] = Emptybuild (e:ls) = insert e (build ls)flatten Empty = []flatten (Node t1 n t2) = (flatten t1) ++ (n : (flatten t2))

data Tree a = Empty | Node (Tree a) a (Tree a)sort :: (Ord a) => [a] -> [a]build :: (Ord a) => [a] -> Tree ainsert :: (Ord a) => a -> Tree a -> Tree aflatten :: Tree a -> [a]sort ls = flatten (build ls)insert e Empty = Node Empty e Emptyinsert e (Node t1 n t2) | e < n = Node (insert e t1) n t2 | e >= n = Node t1 n (insert e t2)

build list = foldr insert Empty list

flatten tree = foldTree (:) [] tree

foldTree :: (a -> b -> b) -> b -> Tree a -> bfoldTree _ seed Empty = seedfoldTree f seed (Node t1 n t2) = foldTree f (f n (foldTree f seed t2)) t1