Урок 3. Карринг и ленивые вычисления

12
1 Кубенский А.А. Функциональное программирование. Глава 2. Средства функционального программирования. 2.2. Карринг Частичная параметризация функций plus :: Integer -> Integer -> Integer plus x y = x + y plus2 :: Integer -> Integer plus2 y = 2 + y plus2 :: Integer -> Integer plus2 y = plus 2 y map plus2 [5, 3, 8, 10] => [7, 5, 10, 12] plus2 :: Integer -> Integer plus2 = plus 2 map (plus 2) [5, 3, 8, 10] => [7, 5, 10, 12] plus :: Integer -> (Integer -> Integer) plus x = \y -> x + y plus :: Integer -> Integer -> Integer plus = \x y -> x + y

Upload: -mydls

Post on 12-Aug-2015

130 views

Category:

Education


1 download

TRANSCRIPT

Page 1: Урок 3. Карринг и ленивые вычисления

1Кубенский А.А. Функциональное программирование.

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

2.2. Карринг

Частичная параметризация функций

plus :: Integer -> Integer -> Integerplus x y = x + y

plus2 :: Integer -> Integerplus2 y = 2 + y

plus2 :: Integer -> Integerplus2 y = plus 2 y

map plus2 [5, 3, 8, 10] => [7, 5, 10, 12]

plus2 :: Integer -> Integerplus2 = plus 2

map (plus 2) [5, 3, 8, 10] => [7, 5, 10, 12]

plus :: Integer -> (Integer -> Integer)plus x = \y -> x + y

plus :: Integer -> Integer -> Integerplus = \x y -> x + y

Page 2: Урок 3. Карринг и ленивые вычисления

2Кубенский А.А. Функциональное программирование.

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

Различные формы записи уравнений

comp :: (b -> c) -> (a -> b) -> (a -> c)comp f g = \x -> f (g x)comp :: (b -> c) -> (a -> b) -> a -> ccomp f g x = f (g x)comp :: (b -> c) -> (a -> b) -> (a -> c)comp = \f -> \g -> \x -> f (g x)

Все функции в Haskell – это функции с одним аргументом и одним результатом!

Haskell B. Curry – карринг. «Карринговые» функции – это частично параметризуемые функции.

plus1 :: Integer -> Integer -> Integer -- в карринговой формеplus1 x y = x + y

plus2 :: (Integer, Integer) -> Integer -- не в карринговой формеplus2 (x, y) = x + y

curry plus2 => plus1uncurry plus1 => plus2

curry :: ((a, b) -> c) -> a -> b -> cuncurry :: (a -> b -> c) -> (a, b) -> ccurry f x y = f (x, y)uncurry f (x, y) = f x y

( )( )

Page 3: Урок 3. Карринг и ленивые вычисления

3Кубенский А.А. Функциональное программирование.

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

Сечения

(+) :: (Num a) => a -> a -> a(+) 5 8 -> 13(+) 5 -> \n->5+n(5 +)

raiseList :: (Num a) => [a] -> [a]raiseList = map (1+)lst lst

(+) ? 8 -> \n->n+8(+ 8)

searchList :: (Eq a) => a -> [a] -> BoolsearchList e = (foldr (||) False) . (map (== e))

searchList 5 [1,3,7,5,2]((foldr (||) False) . (map (== 5))) [1,3,7,5,2]foldr (||) False (map (== 5) [1,3,7,5,2])foldr (||) False [1 == 5, 3 == 5, 7 == 5, 5 == 5, 2 == 5]foldr (||) False [False, False, False, True, False]True

Page 4: Урок 3. Карринг и ленивые вычисления

4Кубенский А.А. Функциональное программирование.

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

Еще раз о сортировке списка с помощью дерева

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

build = foldr insert Emptyflatten = foldTree (:) []

Фильтрация списка

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

filter :: (a -> Bool) -> [a] -> [a]filter f = foldr condCons [] where condCons x l = if f x then x:l else l

quicksort :: (Ord a) => [a] -> [a]quicksort [] = []quicksort (x:ls) = (quicksort (filter (< x) ls)) ++ [x] ++ (quicksort (filter (>= x) ls))

list listtree tree

quicksort [] = []quicksort (x:ls) = (quicksort [y | y<-ls, y < x]) ++ [x] ++ (quicksort [y | y<-ls, y >= x])

descartes ls1 ls2 = [(x, y) | x <- ls1, y <- ls2]oddSqrs ls = [x*x | x <- ls, x `mod` 2 == 1]

Page 5: Урок 3. Карринг и ленивые вычисления

5Кубенский А.А. Функциональное программирование.

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

Характеристическая функция множества

type IntSet = (Integer -> Bool)

empty :: IntSetempty e = False

from2to100 :: IntSetfrom2to100 e = (e >= 2) && (e <= 100)

odds :: IntSetodds e = (e `mod` 2 == 1)

conj :: IntSet -> IntSet -> IntSet(s1 `conj` s2) e = (s1 e) && (s2 e)

disj :: IntSet -> IntSet -> IntSet(s1 `disj` s2) e = (s1 e) || (s2 e)

diff :: IntSet -> IntSet -> IntSet(s1 `diff` s2) e = (s1 e) && ! (s2 e)

addElem :: Integer -> IntSet -> IntSetaddElem a s e = (e == a) || (s e)

remElem :: Integer -> IntSet -> IntSetremElem a s e = (e /= a) && (s e)

fromSet :: IntSet -> [Integer] -> [Integer]fromSet =set ls [x | x <- ls, set x]filter

Page 6: Урок 3. Карринг и ленивые вычисления

6Кубенский А.А. Функциональное программирование.

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

Программирование с использованием множеств

remMulties :: Integer -> IntSet -> IntSetremMulties a s e = (s e) && ((e == a) || (e `mod` a /= 0))

remMultList :: [Integer] -> IntSet -> IntSetremMultList ls s = foldr remMulties s ls

first1000 :: IntSetfirst1000 e = (e >= 2) && (e <= 1000)

first1000remMulties 2remMultList [3,5..31] ( )filter ( ) [1..1000]

Page 7: Урок 3. Карринг и ленивые вычисления

7Кубенский А.А. Функциональное программирование.

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

2.3. Ленивые вычисления

Рассмотрим выражение, содержащее операцию дизъюнкции (ИЛИ):

(x == 0) || (y `div` x > 2)

Опасно ли его вычислять при x == 0 ?

Безопасное вычисление – дизъюнкция "по МакКарти" (McCarthy):

if x == 0 then True else y `div` x > 2

(|||) :: Bool -> Bool -> Boola ||| b = if a then True else b

Безопасно ли выражение:

(x == 0) ||| (y `div` x > 2)

Способы передачи аргументов в функцию:

• «по значению» – значение аргумента вычисляется и передается в функцию;• «по ссылке» – аргумент – это переменная, имя которой передается в функцию;• «по наименованию» – значение аргумента вычисляется при каждом обращении к нему в теле функции;• «по необходимости» – значение аргумента вычисляется при первом обращении к нему в теле функции.

Page 8: Урок 3. Карринг и ленивые вычисления

8Кубенский А.А. Функциональное программирование.

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

Энергичные и ленивые вычисления

Энергичные вычисления:

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

(все функции – строгие по всем своим аргументам).

Ленивые вычисления:

аргументы функций не вычисляются до момента входа в функцию; вычисление значения аргумента происходит при первом обращении

к аргументу – когда его значение нужно для выполнения примитивной функции или в момент сопоставления с образцом;

если функция не обращается к аргументу, то его значение не вычисляется.

В языке Haskell все функции и конструкторы – нестрогие (ленивые) за исключением примитивных арифметических и логических операций.

Выражения:(x == 0) || (y `div` x > 2)(x == 0) ||| (y `div` x > 2)

«безопасны», так как и встроенная операция (||), и определенная программистом операция (|||) – ленивые.

Page 9: Урок 3. Карринг и ленивые вычисления

9Кубенский А.А. Функциональное программирование.

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

«Бесконечные» списки

Необычная функция:

listFrom :: Integer -> [Integer]listFrom n = n : (listFrom (n+1))

listFrom 22 : (listFrom 3)2 : (3 : (listFrom 4)) ...В случае «ленивых» конструкторов аргумент может понадобиться в момент сопоставления с образцом:

sumFirst :: Integer -> [Integer] -> IntegersumFirst 0 _ = 0sumFirst n (e:ls) = e + sumFirst (n-1) ls

sumFirst 3 (listFrom 2)sumFirst 3 (2 : (listFrom 3))2 + sumFirst 2 (listFrom 3)2 + sumFirst 2 (3 : (listFrom 4))2 + (3 + sumFirst 1 (listFrom 4))2 + (3 + sumFirst 1 (4 : (listFrom 5)))2 + (3 + (4 + sumFirst 0 (listFrom 5)))2 + (3 + (4 + 0))9

Page 10: Урок 3. Карринг и ленивые вычисления

10Кубенский А.А. Функциональное программирование.

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

Значения и функции, приводящие к образованию «бесконечных» списков

[2..]

[3, 6..]

[x*x | x <- [1..]]

repeat :: a -> [a]repeat e = ls where ls = e : ls

cycle :: [a] -> [a]cycle ls = lis where lis = ls ++ lis

iterate :: (a -> a) -> a -> [a]iterate f e = e : iterate f (f e)

-- repeat 5 => [5,5,5,5,...]

-- cycle [1,2] => [1,2,1,2,...]

-- iterate (+1) 1 => [1,2,3,...]

Page 11: Урок 3. Карринг и ленивые вычисления

11Кубенский А.А. Функциональное программирование.

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

Манипуляции с бесконечными числовыми списками

diff :: (Num a) => [a] -> [a]diff (x:l@(y:ls)) = (y-x) : (diff l)

take 25 (diff [x*x | x <- [1..]])

take 25 (diff (diff [x*x | x <- [1..]]))

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

Page 12: Урок 3. Карринг и ленивые вычисления

12Кубенский А.А. Функциональное программирование.

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

Список простых чисел, полученный способом «решета Эратосфена»

primes :: [Integer]primes = sieve [2..] where sieve (e:ls) = e : (sieve [x | x <- ls, x `mod` e /= 0])

primessieve [2..]2 : (sieve [x | x <- [3..], x `mod` 2 /= 0])2 : (sieve (3:[x | x <- [4..], x `mod` 2 /= 0])2 : (3 : (sieve [x | x <- [z | z <- [4..], z `mod` 2 /= 0], x `mod` 3 /= 0]))...

Поиграем немного со списком простых чисел:

pairs :: [Integer] -> [(Integer, Integer)]pairs (x:l@(y:ls)) = (x,y):(pairs l)

twins :: [(Integer, Integer)]twins = [(x,y) | (x,y) <- pairs primes, y – x == 2]