10.07.2015 Views

Recursion Patterns and Time-analysis - Departamento de ...

Recursion Patterns and Time-analysis - Departamento de ...

Recursion Patterns and Time-analysis - Departamento de ...

SHOW MORE
SHOW LESS

You also want an ePaper? Increase the reach of your titles

YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.

foldr :: (a -> b -> b) -> b -> [a] -> bfoldr f z [] = zfoldr f z (x:xs) = f x (foldr f z xs)For instance, the function that sums the elements in a list is written as sum = foldr (+) 0.This i<strong>de</strong>a can be generalized for any regular type, the difference being that the programmer will have to writethe appropriate parameterized function that encapsulates the recursion pattern. We exemplify this for two differenttypes of binary trees, respectively leaf-labeled <strong>and</strong> no<strong>de</strong>-labeled, <strong>de</strong>fined as follows.data LTree a = Leaf a | Fork (LTree a) (LTree a)data BTree a = Nil | No<strong>de</strong> a (BTree a) (BTree a)Folds over these trees can be captured by the functions cataLTree <strong>and</strong> cataBTree. In or<strong>de</strong>r to <strong>de</strong>fine these functions,one just has to bear in mind that when processing a no<strong>de</strong> the results of performing recursion on the sub-trees of theno<strong>de</strong> are combined with the contents of the no<strong>de</strong> (if any) to give the final result.cataLTree :: (b -> b -> b) -> (a->b) -> LTree a -> bcataLTree f g (Leaf x) = g xcataLTree f g (Fork l r) = f l’ r’ where l’ = cataLTree f g lr’ = cataLTree f g rcataBTree :: (a -> b -> b -> b) -> b -> BTree a -> bcataBTree f z Nil = zcataBTeee f z (No<strong>de</strong> x l r) = f x l’ r’ where l’ = cataBTeee f z lr’ = cataBTeee f z rOften the arguments of these functions are called the genes of the folds. In the case of binary trees, the genes are pairsof functions, the first of which is used to process no<strong>de</strong>s, <strong>and</strong> the second to process leaves (in fact, for no<strong>de</strong>-labeledtrees, this second component is a constant since there is no information to process in an empty leaf).As examples of folds over trees, let us write the height functions for both types of trees.heightLTree = cataLTree (\ l r -> 1 + (max l r)) (\_ -> 0)heightBTree = cataBTree (\x l r -> 1 + (max l r)) 0Unfolds. In the context of a programming language with non-strict semantics such as Haskell, recursive <strong>and</strong> corecursivetypes coinci<strong>de</strong>. Unfolds st<strong>and</strong> to corecursive programs as folds st<strong>and</strong> to recursive programs (they are dualconcepts); they are however less wi<strong>de</strong>ly used by programmers [4]. Consi<strong>de</strong>r the Haskell function that constructs (wheninvoked with 0) a binary tree where each no<strong>de</strong> is labeled with its <strong>de</strong>pth in the tree, stopping at level 100.inflevels100 100 = Nilinflevels100 n = No<strong>de</strong> n (inflevels100 (n+1)) (inflevels100 (n+1))This function has the property that when a no<strong>de</strong> is returned, both its sub-trees are recursively constructed by thesame function being <strong>de</strong>fined. This clearly indicates that a corecursion pattern is being used, which can be writtenonce <strong>and</strong> for all. The following functions capture these patterns for both types of trees we have been using:anaLTree :: (b -> (Either a (b,b))) -> b -> LTree aanaLTree h x = case (h x) of Left y -> Leaf yRight (a,b) -> Fork (anaLTree h a) (anaLTree h b)anaBTree :: (a -> Maybe (b,a,a)) -> a -> BTree banaBTree h x = case (h x) of Nothing -> NilJust (y,a,b) -> No<strong>de</strong> y (anaBTree h a) (anaBTree h b)

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!