120 likes | 321 Views
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].
E N D
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 Кубенский А.А. Функциональное программирование. Глава 2. Средства функционального программирования.
Различные формы записи уравнений comp :: (b -> c) -> (a -> b) -> (a -> c) comp f g = \x -> f (g x) comp :: (b -> c) -> (a -> b) -> a -> c comp f g x = f (g x) comp :: (b -> c) -> (a -> b) -> (a -> c) comp = \f -> \g -> \x -> f (g x) Все функции в Haskell – это функции с одним аргументом и одним результатом! HaskellB. Curry – карринг. «Карринговые» функции – это частично параметризуемые функции. plus1 :: Integer -> Integer -> Integer -- в карринговой форме plus1 x y = x + y plus2 :: (Integer, Integer) -> Integer -- не в карринговой форме plus2 (x, y) = x + y curry plus2 => plus1 uncurry plus1 => plus2 curry :: ((a, b) -> c) -> a -> b -> c uncurry :: (a -> b -> c) -> (a, b) -> c curry f x y = f (x, y) uncurry f (x, y) = f x y ( ) ( ) Кубенский А.А. Функциональное программирование. Глава 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] -> Bool searchList 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 Кубенский А.А. Функциональное программирование. Глава 2. Средства функционального программирования.
Еще раз о сортировке списка с помощью дерева build :: (Ord a) => [a] -> Tree a insert :: (Ord a) => a -> Tree a -> Tree a flatten :: Tree a -> [a] build = foldr insert Empty flatten = foldTree (:) [] list list tree tree Фильтрация списка 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)) 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] Кубенский А.А. Функциональное программирование. Глава 2. Средства функционального программирования.
Характеристическая функция множества type IntSet = (Integer -> Bool) empty :: IntSet empty e = False from2to100 :: IntSet from2to100 e = (e >= 2) && (e <= 100) odds :: IntSet odds 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 -> IntSet addElem a s e = (e == a) || (s e) remElem :: Integer -> IntSet -> IntSet remElem a s e = (e /= a) && (s e) fromSet :: IntSet -> [Integer] -> [Integer] fromSet = set ls [x | x <- ls, set x] filter Кубенский А.А. Функциональное программирование. Глава 2. Средства функционального программирования.
Программирование с использованием множеств remMulties :: Integer -> IntSet -> IntSet remMulties a s e = (s e) && ((e == a) || (e `mod` a /= 0)) remMultList :: [Integer] -> IntSet -> IntSet remMultList ls s = foldr remMulties s ls first1000 :: IntSet first1000 e = (e >= 2) && (e <= 1000) filter ( remMultList [3,5..31] ( remMulties 2 first1000 ) ) [1..1000] Кубенский А.А. Функциональное программирование. Глава 2. Средства функционального программирования.
2.3. Ленивые вычисления Рассмотрим выражение, содержащее операцию дизъюнкции (ИЛИ): (x == 0) || (y `div` x > 2) Опасно ли его вычислять при x == 0 ? Безопасное вычисление – дизъюнкция "по МакКарти" (McCarthy): if x == 0 then True else y `div` x > 2 (|||) :: Bool -> Bool -> Bool a ||| b = if a then True else b Безопасно ли выражение: (x == 0) ||| (y `div` x > 2) • Способы передачи аргументов в функцию: • «по значению» – значение аргумента вычисляется и передается в функцию; • «по ссылке» – аргумент – это переменная, имя которой передается в функцию; • «по наименованию» – значение аргумента вычисляется • при каждом обращении к нему в теле функции; • «по необходимости» – значение аргумента вычисляется • при первом обращении к нему в теле функции. Кубенский А.А. Функциональное программирование. Глава 2. Средства функционального программирования.
Энергичные и ленивые вычисления • Энергичные вычисления: • аргументы всех функций вычисляются до момента входа в функцию; • если аргумент не может быть вычислен, то значение функции не определено (все функции – строгие по всем своим аргументам). • Ленивые вычисления: • аргументы функций не вычисляются до момента входа в функцию; • вычисление значения аргумента происходит при первом обращении к аргументу – когда его значение нужно для выполнения примитивной функции или в момент сопоставления с образцом; • если функция не обращается к аргументу, то его значение не вычисляется. В языке Haskell все функции и конструкторы – нестрогие (ленивые) за исключением примитивных арифметических и логических операций. Выражения: (x == 0) || (y `div` x > 2) (x == 0) ||| (y `div` x > 2) «безопасны», так как и встроенная операция (||),и определенная программистом операция (|||) – ленивые. Кубенский А.А. Функциональное программирование. Глава 2. Средства функционального программирования.
«Бесконечные» списки Необычная функция: listFrom :: Integer -> [Integer] listFrom n = n : (listFrom (n+1)) listFrom 2 2 : (listFrom 3) 2 : (3 : (listFrom 4)) ... В случае «ленивых» конструкторов аргумент может понадобиться в момент сопоставления с образцом: sumFirst :: Integer -> [Integer] -> Integer sumFirst 0 _ = 0 sumFirst 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 Кубенский А.А. Функциональное программирование. Глава 2. Средства функционального программирования.
Значения и функции, приводящие к образованию «бесконечных» списков [2..] [3, 6..] [x*x | x <- [1..]] repeat :: a -> [a] repeat e = ls where ls = e : ls -- repeat 5 => [5,5,5,5,...] cycle :: [a] -> [a] cycle ls = lis where lis = ls ++ lis -- cycle [1,2] => [1,2,1,2,...] iterate :: (a -> a) -> a -> [a] iterate f e = e : iterate f (f e) -- iterate (+1) 1 => [1,2,3,...] Кубенский А.А. Функциональное программирование. Глава 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..]])) Кубенский А.А. Функциональное программирование. Глава 2. Средства функционального программирования.
Список простых чисел, полученный способом «решета Эратосфена» primes :: [Integer] primes = sieve [2..] where sieve (e:ls) = e : (sieve [x | x <- ls, x `mod` e /= 0]) primes sieve [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] Кубенский А.А. Функциональное программирование. Глава 2. Средства функционального программирования.