Эффективность рекурсивных функций.
description
Transcript of Эффективность рекурсивных функций.
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
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)
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
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
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)
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
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)
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
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)
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)
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)
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))
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]
14Кубенский А.А. Функциональное программирование.Глава 2. Средства функционального программирования.
Определение функций с помощью λ-выражений
λ-исчисление Черча – исчисление безымянных функций
sqr : λx.* x x
sqr = \x -> (x * x)
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 ... ...
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)
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
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
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
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
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