Recursion involves a self-calling functions. Lots of functions in Haskell should be written like this as it allows for a very elegant representation of what a function does rather than how to compute it.
-- Maximum function
maximum' xs = case xs of [] -> eror "Maximum of empty list"
[x] = x
x:xs = max x (maximum' x)
When trying to define a function recursively, first start with the base case, then think about the algorithm in a trivial case and how that can be implemented in code, think about it abstractly, make sure all situations are covered.
Quicksort:
-- this ones nice!
-- quicksort only works on types which can be compared: i.e. are of the Ord type class
quicksort :: (Ord a) => [a] -> [a]
quicksort [] = [] -- base case
-- using the first part of the list as the pivot
quicksort x:xs =
let smallerOrEqual = [ a | a <- xs, a <= x]
larger = [ a | a <- xs, a > x]
in quicksort smallerOrEqual ++ [x] ++ quicksort larger
Ah beautiful.