210 likes | 316 Views
Triedenie s banánmi, šošovkami a obálkami. d nes u ž k triedeniu príde... Erik Meijer, Maarten Fokkinga, Ross Paterson: Functional Programming with Bananas, Lenses, Envelopes and Barbed Wire
E N D
Triedenie s banánmi, šošovkami a obálkami dnes už k triedeniu príde... • Erik Meijer, Maarten Fokkinga, Ross Paterson: Functional Programming with Bananas, Lenses, Envelopes and Barbed Wire • Lex Augusteijn: Sorting morfizmuss, LNCS 1608, 3rd Int.School of Advanced Functional Programming, 1998 • Schémy rekurzie: • catamorfizmus • anamorfizmus • hylomorfizmus
List-anamorfizmus ana (upwards as anabolismus) anamorfizmus alias lenses[( )], unfold list-anamorfizmus je funkcia typu b -> [a]: • deštruuj b, • komponenty typu U rekurzívne konvertuj do [a], • skombinuj výsledky typu [a] do výsledku typu [a]. list_ana1 :: (b->Bool) -> (b -> (a,b)) -> b -> [a] list_ana1 p g b | p b = [] -- ak p b, tak končí rekuzia (terminátor) | otherwise = a:list_ana1 p g b' where (a,b') = g b-- g je nextor -- a je prvok do výsledného zoznamu -- b' je argument na rekurzívne volanie list_ana1
zip list_ana1 :: (b->Bool) -> (b -> (a,b)) -> b -> [a] Definujme zip1 :: ([x],[y]) -> [(x,y)] pomocou list_ana1: ujasnime si typy... b = ([x],[y]) a = (x,y) p :: ([x],[y]) -> Bool g :: ([x],[y]) -> ( (x,y) , ([x],[y]) ) zip1 :: ([x],[y]) -> [(x,y)] zip1 = list_ana1 p g where p ([],_) = True -- True, ak končí rekuzia p (_,[]) = True p (_,_) = False g (a:as, b:bs) = ((a,b), (as,bs)) -- (a,b) je prvok do výsledneho zoznamu -- as,bs je argument na rekurzívne volanie list_ana1 zip1 ([1,2,3],[11,22,33]) [(1,11),(2,22),(3,33)]
iterate, map list_ana1 :: (b->Bool) -> (b -> (a,b)) -> b -> [a] Definujte iterate1 :: (x -> x) -> x -> [x] pomocou list_ana1, aby iterate1 f a = [a, f a, f f a, f f f a, ...] ujasnime si typy: • b = a = x • p :: (x -> Bool) - terminátor • g :: x -> (x,x) - nextor iterate1 f = list_ana1 p g where p_ = False -- never ending... g a = (a,f a)-- a je prvok do výsledneho zoznamu -- (f a) je argumentna rekurzívne volanie list_ana1 map1 f = list_ana1 p g where p [] = True p _ = False g (a:as) = (f a, as)-- f a je prvok do výsledneho zozn. -- as je argumentna rekurzívne volanie list_ana1 take 10 (iterate1 (+1) 5) [5,6,7,8,9,10,11,12,13,14]
List-coalgebra Either je súčet typov (union type) s tagmi Left a Right: • data Either a b = = Left a | Right b type List_coalg b a = b -> Either () (a, b) -- dosadíme Left () | Right (a, b) List_coalg je p(terminátor) aj g (nextor) dokopy: • ak list_coalg b = Left _, tak p b = True, • ak list_coalg b = Right(a, b'), tak (a, b') = g b list_ana2 :: List_coalg b a -> b -> [a] list_ana2 lca = ana where ana u = case lca u of Left _ -> [] -- vtedy končíme, lca u = Left _ Right (a,b') -> a : ana b' -- lca u = Right (a,b’), t.j. g b = (a,b’)
List-coalgebra list_ana2 :: List_coalg b a -> b -> [a] destruct_count 0 = Left ()– kedy končíme destruct_count n = Right (n,n-1) – n ide do výsledku – na n-1 ide rekurzia count :: Integer -> [Integer] count = list_ana2 destruct_count iterate2 f = list_ana2 (\a -> Right (a,f a)) map2 f = list_ana2 destruct_list where destruct_list [] = Left () destruct_list (a:as)= Right(f a, as) count 5 [5,4,3,2,1] take 10 (iterate2 (+1) 0) [0,1,2,3,4,5,6,7,8,9] map2 (+1) [1..10] [2,3,4,5,6,7,8,9,10,11]
List-coalgebra’ – iná syntax type List_coalg b a = b -> Either () (a, b) ==== b -> Left () | Right (a,b) data Either' x = True' | False' x – predefinujem náš vlastný Either type List_coalg' b a = b -> Either' (a, b) type List_coalg' b a = b -> Either' (a, b) = b -> True' | False' (a,b) list_ana2' :: List_coalg' b a -> b -> [a] list_ana2' lca = ana where ana u = case lca u of True' -> [] False' (a,b') -> a : ana b' count' = list_ana2' destruct_count where destruct_count 0 = True' destruct_count n = False' (n,n-1)
unfoldr (List.hs) data Either' x = True' | False' x data Maybe a = Nothing | Just a– v haskelli, Prelude.hs deriving (Eq, Ord, Read, Show) unfoldr :: (b -> Maybe (a, b)) -> b -> [a] unfoldr f b = case f b of Just (a,b’) -> a : unfoldr f b’ Nothing -> [] count'' = unfoldr destruct_count where destruct_count 0 = Nothing destruct_count n = Just (n,n-1) iterate' f = unfoldr (\a -> Just (a, f a))
prime Definujte prime ako anamorfizmus prime = sieve [2..] where sieve = list_ana2 destruct_prime where destruct_prime (x:xs) = Right(x, [y | y <-xs, y `mod` x > 0]) prime' = sieve [2..] where sieve = list_ana2 ' destruct_prime where destruct_prime (x:xs) = False'(x, [y | y <-xs, y `mod` x > 0]) take 100 prime [2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,...] Cvičenie-1: Definujte [1,2,4,8,...,2n, ...] ako anamorfizmus. Cvičenie-2: Definujte [1,3,7,15,..., 2n-1, ...] ako anamorfizmus. Cvičenie-3: Definujte [1,2, 6, 24,..., n!, ...] ako anamorfizmus.
x:l insert-sort destruct x l recurse Definujte insert-sort ako list-catamorfizmus (foldr) insert_sort x = list_cata2 ([], insert) x where insert a [] = [a] insert a (x:xs) | a < x = a:x:xs | otherwise = x : insert a xs insert :: Int -> [Int] -> [Int] -- inak, cez foldr insert_sort' :: [Int] -> [Int] insert_sort' = foldr insert [] x sort l insert insert x (sort l) insert_sort [2,2,1,34,5,2,4,23,2,4] [1,2,2,2,2,4,4,5,23,34] Cvičenie-4: Viete definovať insert ako list-cata resp. ana-morfizmus?
l min-sort extract minimum m l’ recurse Definujte min-sort ako list-anamorfizmus selection_sort extract = list_ana2 select where select [] = Left () select x = Right (extract x) -- dummy extract, prvy extra (x:xs) = (x,xs) min_sort xs = selection_sort extract_min xs where extract_min ls = (m, remove m ls) where m = minimum ls remove x [] = [] remove x (y:ls) | x == y = ls | otherwise = y : remove x ls m sort l’ construct m:(sort l’) selection_sort extra [4,3,2,4,2,1,3] [4,3,2,4,2,1,3] min_sort [4,3,2,4,2,1,3] [1,2,2,3,3,4,4] Cvičenie-4: Viete definovaťremove ako list-cata resp. ana-morfizmus?
l buble-sort buble m l’ recurse Definujme buble_sort ako selection_sort buble_sort ls = selection_sort extract_buble ls where extract_buble [x] = (x, []) extract_buble (x:ls) = if x < y then (x,y:m) else (y,x:m) where (y,m) = extract_buble ls -- definujme extract_buble ako cata-morfizmus buble_sort' ls = selection_sort extract_buble ls where extract_buble (x:ls) = list_cata2 ((x,[]), bub) ls bub x (y,ls) = if x < y then (x,y:ls) else (y,x:ls) m sort l’ construct m:(sort l’) buble_sort [4,3,2,4,2,1,3] [1,2,2,3,3,4,4] buble_sort' [4,3,2,4,2,1,3] [1,2,2,3,3,4,4]
Hurá na stromy 1 … aby sme objavili nelinearne patterny rekuzie data LeafTree x = Leaf x | Node (LeafTree x) (LeafTree x) deriving(Show, Read, Eq) -- príklad rekurzie tree_sum (Leaf x) = x tree_sum (Node l r) = tree_sum l + tree_sum r type Leaftree_alg x u = (x -> u, u -> u -> u) leaftree_cata :: Leaftree_alg x u -> LeafTree x -> u leaftree_cata(fl, fs) = cata where cata (Leaf x) = fl x cata (Node l r) = fs (cata l) (cata r) – príklad tree_sum' = leaftree_cata (id,(+)) 7 9
Ana na strome type Leaftree_coalg b a = b -> Either a (b,b) leaftree_ana :: Leaftree_coalg b a -> b -> LeafTree a leaftree_ana lftca = ana where ana t = case lftca t of Left l -> Leaf l Right (l,r)-> Node(ana l) (ana r)
Fib tree 1 1 1 fib_tree n | n < 2 = Leaf 1 | otherwise = Node (fib_tree (n-1)) (fib_tree (n-2)) – ako ana-morfizmus fib_tree' = leaftree_ana destruct_fib where destruct_fib n | n < 2 = Left 1 | otherwise = Right (n-1, n-2) 1 1 fib_tree 4 Node (Node (Node (Leaf 1) (Leaf 1)) (Leaf 1)) (Node (Leaf 1) (Leaf 1))
Hylo-morfizmus (ana . cata) type Leaftree_hylo u x v = (Leaftree_coalg u x, Leaftree_alg x v) leaftree_hylo :: Leaftree_hylo u x v -> u -> v leaftree_hylo (d, (fl, fs)) = hylo where hylo t = case d t of Left l -> fl l -- (Leaf l) -> applikuj fl Right (l,r) -> fs (hylo l) (hylo r) -- (Node l r) -> applikuj fs fib = tree_sum' . fib_tree' fib' = leaftree_hylo (destruct_fib, (id, (+))) Cvičenie-5: Definujte n! ako leaftree hylo-morfizmus. Cvičenie-6: Definujte xn ako leaftree hylo-morfizmus.
List-hylomorfizmus list_hylo1 a c = (list_cata2 c) . (list_ana2 a) prod = list_cata2 (1, (*)) fact3 = (list_cata2 (1, (*))) . (list_ana2 destruct_count) fact3' = prod . count fact3'' = list_hylo1 destruct_count (1, (*)) Cvičenie-7: Definujte xn ako list hylo-morfizmus.
merge-sort 4 2 3 1 merge_sort [] = [] merge_sort xs = leaftree_hylo (select, (single, merge)) xs where single x = [x] merge (x:xs) (y:ys) | x < y = x:merge xs (y:ys) | otherwise = y : merge (x:xs) ys merge [] m = m merge m [] = m select [x] = Left x select l = Right (split l) split = list_cata2 (([],[]),f) where f x (l,r) = (r, x:l) split [1..10] ([2,4,6,8,10],[1,3,5,7,9]) leaftree_ana select [1..4] Node (Node (Leaf 4) (Leaf 2)) (Node (Leaf 3) (Leaf 1))
Binárny strom 3 1 8 data BinaryTree x = Nil | Branch x (BinaryTree x) (BinaryTree x) type BinaryTree_alg x u = (u, x->u->u->u) bintree_cata :: BinaryTree_alg x u -> BinaryTree x -> u bintree_cata (a,f) = cata where cata Nil = a cata (Branch x l r) = f x (cata l) (cata r) type BinaryTree_coalg u x = u->Either () (x,u,u) bintree_ana :: BinaryTree_coalg u x -> u -> BinaryTree x bintree_ana btca= ana where ana t = case btca t of Left _ -> Nil Right (x,l,r) -> Branch x (ana l) (ana r) Cvičenie-8: Definujte bintree_hylo ako binarytree hylo-morfizmus. 7 9
quick-sort quick_sort l = bintree_hylo (split, ([], join)) l where split [] = Left () split (x:l) = Right (x, smaller, greater) where (smaller,greater) = partition' (<x) l join x l r = l ++ x : r partition' p l = list_cata2 (([],[]),f) l where f x (a, b) = if p x then (x:a,b) else (a,x:b) Cvičenie-9: Cvičenie-10: Definujte n! ako bintree hylo-morfizmus. Cvičenie-11: Definujte xn ako bintree hylo-morfizmus. Cvičenie-12: Definujte hanojské veže ako bintree hylo-morfizmus.
para-morfizmus type List_para x u = (u, x->[x]->u->u) list_para :: List_para x u -> [x] -> u list_para (a,f) = para where para [] = a para (x:l) = f x l (para l) insert'' x= list_para ([x],combine) where combine a l rec | x < a = x:a:l | otherwise = a:rec insert_sort'' x = list_cata2 ([], insert'') x Cvičenie-13: Definujte remove ako list para-morfizmus.