Recursion or Iteration?

前端 未结 30 2098
小鲜肉
小鲜肉 2020-11-22 14:44

Is there a performance hit if we use a loop instead of recursion or vice versa in algorithms where both can serve the same purpose? Eg: Check if the given string is a palind

30条回答
  •  南笙
    南笙 (楼主)
    2020-11-22 15:10

    I'm going to answer your question by designing a Haskell data structure by "induction", which is a sort of "dual" to recursion. And then I will show how this duality leads to nice things.

    We introduce a type for a simple tree:

    data Tree a = Branch (Tree a) (Tree a)
                | Leaf a
                deriving (Eq)
    

    We can read this definition as saying "A tree is a Branch (which contains two trees) or is a leaf (which contains a data value)". So the leaf is a sort of minimal case. If a tree isn't a leaf, then it must be a compound tree containing two trees. These are the only cases.

    Let's make a tree:

    example :: Tree Int
    example = Branch (Leaf 1) 
                     (Branch (Leaf 2) 
                             (Leaf 3))
    

    Now, let's suppose we want to add 1 to each value in the tree. We can do this by calling:

    addOne :: Tree Int -> Tree Int
    addOne (Branch a b) = Branch (addOne a) (addOne b)
    addOne (Leaf a)     = Leaf (a + 1)
    

    First, notice that this is in fact a recursive definition. It takes the data constructors Branch and Leaf as cases (and since Leaf is minimal and these are the only possible cases), we are sure that the function will terminate.

    What would it take to write addOne in an iterative style? What will looping into an arbitrary number of branches look like?

    Also, this kind of recursion can often be factored out, in terms of a "functor". We can make Trees into Functors by defining:

    instance Functor Tree where fmap f (Leaf a)     = Leaf (f a)
                                fmap f (Branch a b) = Branch (fmap f a) (fmap f b)
    

    and defining:

    addOne' = fmap (+1)
    

    We can factor out other recursion schemes, such as the catamorphism (or fold) for an algebraic data type. Using a catamorphism, we can write:

    addOne'' = cata go where
               go (Leaf a) = Leaf (a + 1)
               go (Branch a b) = Branch a b
    

提交回复
热议问题