A few others have given more complete walkthroughs / traces of the executions, but just to add a little. When it finally "clicked" with me and recursion became easier to understand, it was when I stopped trying to think about the entire execution chain. For example, let's say I run a ticket resale (scalping) shop and someone calls me and says "hey I need two tickets for the show this saturday." I tell the guy sure no problem, I'll call you back in 2 hours. But actually I don't have the tickets, so I call one of my connections. Unfortunately, he doesn't have the tickets either so this process ends up repeating for a while. When I talk to my connection on the phone I don't think "ok he's going to call John, and John's probably going to call William, and then William might call Frank, etc". I just think "he's either going to call me back and say yes or no, regardless of how he arrives at that answer". That's the key to recursion.
In the case of finding the maximum element of a list, just imagine breaking the list into two pieces. The first piece is the first item in the list, and the second piece is everything else. If everything else is empty, then the first piece is trivially the maximum, it only has one element. Otherwise, compare the first element to the max of everything else. Take whichever one is bigger. The entire chain of stuff that happens as a result of "the max of everything else", isn't important. The important thing is that IF you have the first element, and IF you have the max of everything else, then the max of the whole list is the greater of those two items.
Hi Adrian,
Thanks for the explanations. Could we perhaps examine one recursive example in detail, i.e., step-by-step, as I'm still confused? Maybe the following program from chapter 2 of
http://book.realworldhaskell.org?
myDrop n xs = if n <= 0 || null xs
then xs
else myDrop (n - 1) (tail xs)
Danke,
Caitlin
--- On Wed, 3/18/09, Adrian Neumann <aneumann@inf.fu-berlin.de> wrote:
From: Adrian Neumann <aneumann@inf.fu-berlin.de>
Subject: Re: [Haskell-beginners] Understanding recursion in Haskell.
To: beginners@haskell.org
Date: Wednesday, March 18, 2009, 12:05 AM
-----Inline Attachment Follows-----
Am 18.03.2009 um 06:28 schrieb Caitlin:
>
> Hi.
>
> As a Haskell
beginner, I was wondering if someoneone could explain how the following programs function (pardon the pun)?
>
This function takes some type which has an ordering defined, i.e. you can compare its elements to one another
> maximum' :: (Ord a) => [a] -> a
it doesn't work for an empty list
> maximum' [] = error "maximum of empty list"
the maximum of a one element list is the lone element. this is the base case which will be eventually reached by the recursion
> maximum' [x] = x
should the list have more than one element
> maximum' (x:xs)
compare the first element to the maximum of the other elements. if it's greater, it's the maximum
> | x > maxTail = x
otherwise the maximum of the other elements is the maximum of the whole list
> | otherwise = maxTail
how to compute the maximum of the other elements? just use
this function again. after a while we will only have one element left and reach the base case above.
> where maxTail = maximum' xs
>
>
This function takes a number and a list of some type a
> take' :: (Num i, Ord i) => i -> [a] -> [a]
first, ignore the list and check whether n is <= 0. in this case return an empty list. this is the base case, that's eventually reached by the recursion
> take' n _
> | n <= 0 = []
otherwise, check if the list is empty. this is another base case.
> take' _ [] = []
if neither n<=0 or the list empty, take the first element, x, and put it on front of the prefix of length (n-1) of the other elements. use take' again, to get that prefix. after a while either n is 0 or there are no more elements in the list and we reach the base case
> take' n (x:xs) = x : take' (n-1) xs
>
>
Take two lists
>
> zip' :: [a] -> [b] -> [(a,b)]
if either one of them is empty, stop
> zip' _ [] = []
> zip' [] _ = []
otherwise prepend a tuple, build from the two first elements to the zipped list of the other elements. after a while one of the lists should become empty and the base case is reached.
> zip' (x:xs) (y:ys) = (x,y):zip' xs ys
>
>
>
> quicksort :: (Ord a) => [a] -> [a]
empty list -> nothing to do
> quicksort [] = []
> quicksort (x:xs) =
otherwise take the first element of the list and use it to split the list in two halves. one with all the elements that are smaller or equal than x, the other one with all those that are bigger. now sort them and put x in the middle. that should give us a sorted whole. how to sort them? just use quicksort again! after some splitting the lists will become empty
and the recursion stops.
> let smallerSorted = quicksort [a | a <- xs, a <= x]
> biggerSorted = quicksort [a | a <- xs, a > x]
> in smallerSorted ++ [x] ++ biggerSorted
_______________________________________________
Beginners mailing list
Beginners@haskell.org
http://www.haskell.org/mailman/listinfo/beginners
_______________________________________________
Beginners mailing list
Beginners@haskell.org
http://www.haskell.org/mailman/listinfo/beginners