Related
If I create a infinite list like this:
let t xs = xs ++ [sum(xs)]
let xs = [1,2] : map (t) xs
take 10 xs
I will get this result:
[
[1,2],
[1,2,3],
[1,2,3,6],
[1,2,3,6,12],
[1,2,3,6,12,24],
[1,2,3,6,12,24,48],
[1,2,3,6,12,24,48,96],
[1,2,3,6,12,24,48,96,192],
[1,2,3,6,12,24,48,96,192,384],
[1,2,3,6,12,24,48,96,192,384,768]
]
This is pretty close to what I am trying to do.
This current code uses the last value to define the next. But, instead of a list of lists, I would like to know some way to make an infinite list that uses all the previous values to define the new one.
So the output would be only
[1,2,3,6,12,24,48,96,192,384,768,1536,...]
I have the definition of the first element [1].
I have the rule of getting a new element, sum all the previous elements.
But, I could not put this in the Haskell grammar to create the infinite list.
Using my current code, I could take the list that I need, using the command:
xs !! 10
> [1,2,3,6,12,24,48,96,192,384,768,1536]
But, it seems to me, that it is possible doing this in some more efficient way.
Some Notes
I understand that, for this particular example, that was intentionally oversimplified, we could create a function that uses only the last value to define the next.
But, I am searching if it is possible to read all the previous values into an infinite list definition.
I am sorry if the example that I used created some confusion.
Here another example, that is not possible to fix using reading only the last value:
isMultipleByList :: Integer -> [Integer] -> Bool
isMultipleByList _ [] = False
isMultipleByList v (x:xs) = if (mod v x == 0)
then True
else (isMultipleByList v xs)
nextNotMultipleLoop :: Integer -> Integer -> [Integer] -> Integer
nextNotMultipleLoop step v xs = if not (isMultipleByList v xs)
then v
else nextNotMultipleLoop step (v + step) xs
nextNotMultiple :: [Integer] -> Integer
nextNotMultiple xs = if xs == [2]
then nextNotMultipleLoop 1 (maximum xs) xs
else nextNotMultipleLoop 2 (maximum xs) xs
addNextNotMultiple xs = xs ++ [nextNotMultiple xs]
infinitePrimeList = [2] : map (addNextNotMultiple) infinitePrimeList
take 10 infinitePrimeList
[
[2,3],
[2,3,5],
[2,3,5,7],
[2,3,5,7,11],
[2,3,5,7,11,13],
[2,3,5,7,11,13,17],
[2,3,5,7,11,13,17,19],
[2,3,5,7,11,13,17,19,23],
[2,3,5,7,11,13,17,19,23,29],
[2,3,5,7,11,13,17,19,23,29,31]
]
infinitePrimeList !! 10
[2,3,5,7,11,13,17,19,23,29,31,37]
You can think so:
You want to create a list (call them a) which starts on [1,2]:
a = [1,2] ++ ???
... and have this property: each next element in a is a sum of all previous elements in a. So you can write
scanl1 (+) a
and get a new list, in which any element with index n is sum of n first elements of list a. So, it is [1, 3, 6 ...]. All you need is take all elements without first:
tail (scanl1 (+) a)
So, you can define a as:
a = [1,2] ++ tail (scanl1 (+) a)
This way of thought you can apply with other similar problems of definition list through its elements.
If we already had the final result, calculating the list of previous elements for a given element would be easy, a simple application of the inits function.
Let's assume we already have the final result xs, and use it to compute xs itself:
import Data.List (inits)
main :: IO ()
main = do
let is = drop 2 $ inits xs
xs = 1 : 2 : map sum is
print $ take 10 xs
This produces the list
[1,2,3,6,12,24,48,96,192,384]
(Note: this is less efficient than SergeyKuz1001's solution, because the sum is re-calculated each time.)
unfoldr has a quite nice flexibility to adapt to various "create-a-list-from-initial-conditions"-problems so I think it is worth mentioning.
A little less elegant for this specific case, but shows how unfoldr can be used.
import Data.List
nextVal as = Just (s,as++[s])
where s = sum as
initList = [1,2]
myList =initList ++ ( unfoldr nextVal initList)
main = putStrLn . show . (take 12) $ myList
Yielding
[1,2,3,6,12,24,48,96,192,384,768,1536]
in the end.
As pointed out in the comment, one should think a little when using unfoldr. The way I've written it above, the code mimicks the code in the original question. However, this means that the accumulator is updated with as++[s], thus constructing a new list at every iteration. A quick run at https://repl.it/languages/haskell suggests it becomes quite memory intensive and slow. (4.5 seconds to access the 2000nd element in myList
Simply swapping the acumulator update to a:as produced a 7-fold speed increase. Since the same list can be reused as accumulator in every step it goes faster. However, the accumulator list is now in reverse, so one needs to think a little bit. In the case of predicate function sum this makes no differece, but if the order of the list matters, one must think a little bit extra.
You could define it like this:
xs = 1:2:iterate (*2) 3
For example:
Prelude> take 12 xs
[1,2,3,6,12,24,48,96,192,384,768,1536]
So here's my take. I tried not to create O(n) extra lists.
explode ∷ Integral i ⇒ (i ->[a] -> a) -> [a] -> [a]
explode fn init = as where
as = init ++ [fn i as | i <- [l, l+1..]]
l = genericLength init
This convenience function does create additional lists (by take). Hopefully they can be optimised away by the compiler.
explode' f = explode (\x as -> f $ take x as)
Usage examples:
myList = explode' sum [1,2]
sum' 0 xs = 0
sum' n (x:xs) = x + sum' (n-1) xs
myList2 = explode sum' [1,2]
In my tests there's little performance difference between the two functions. explode' is often slightly better.
The solution from #LudvigH is very nice and clear. But, it was not faster.
I am still working on the benchmark to compare the other options.
For now, this is the best solution that I could find:
-------------------------------------------------------------------------------------
-- # infinite sum of the previous using fuse
-------------------------------------------------------------------------------------
recursiveSum xs = [nextValue] ++ (recursiveSum (nextList)) where
nextValue = sum(xs)
nextList = xs ++ [nextValue]
initialSumValues = [1]
infiniteSumFuse = initialSumValues ++ recursiveSum initialSumValues
-------------------------------------------------------------------------------------
-- # infinite prime list using fuse
-------------------------------------------------------------------------------------
-- calculate the current value based in the current list
-- call the same function with the new combined value
recursivePrimeList xs = [nextValue] ++ (recursivePrimeList (nextList)) where
nextValue = nextNonMultiple(xs)
nextList = xs ++ [nextValue]
initialPrimes = [2]
infiniteFusePrimeList = initialPrimes ++ recursivePrimeList initialPrimes
This approach is fast and makes good use of many cores.
Maybe there is some faster solution, but I decided to post this to share my current progress on this subject so far.
In general, define
xs = x1 : zipWith f xs (inits xs)
Then it's xs == x1 : f x1 [] : f x2 [x1] : f x3 [x1, x2] : ...., and so on.
Here's one example of using inits in the context of computing the infinite list of primes, which pairs them up as
ps = 2 : f p1 [p1] : f p2 [p1,p2] : f p3 [p1,p2,p3] : ...
(in the definition of primes5 there).
I need a function to double every other number in a list. This does the trick:
doubleEveryOther :: [Integer] -> [Integer]
doubleEveryOther [] = []
doubleEveryOther (x:[]) = [x]
doubleEveryOther (x:(y:zs)) = x : 2 * y : doubleEveryOther zs
However, the catch is that I need to double every other number starting from the right - so if the length of the list is even, the first one will be doubled, etc.
I understand that in Haskell it's tricky to operate on lists backwards, so my plan was to reverse the list, apply my function, then output the reverse again. I have a reverseList function:
reverseList :: [Integer] -> [Integer]
reverseList [] = []
reverseList xs = last xs : reverseList (init xs)
But I'm not quite sure how to implant it inside my original function. I got to something like this:
doubleEveryOther :: [Integer] -> [Integer]
doubleEveryOther [] = []
doubleEveryOther (x:[]) = [x]
doubleEveryOther (x:(y:zs)) =
| rev_list = reverseList (x:(y:zs))
| rev_list = [2 * x, y] ++ doubleEveryOther zs
I'm not exactly sure of the syntax of a function that includes intermediate values like this.
In case it's relevant, this is for Exercise 2 in CIS 194 HW 1.
This is a very simple combination of the two functions you've already created:
doubleEveryOtherFromRight = reverseList . doubleEveryOther . reverseList
Note that your reverseList is actually already defined in the standard Prelude as reverse. so you didn't need to define it yourself.
I'm aware that the above solution isn't very efficient, because both uses of reverse need to pass through the entire list. I'll leave it to others to suggest more efficient versions, but hopefully this illustrates the power of function composition to build more complex computations out of simpler ones.
As Lorenzo points out, you can make one pass to determine if the list has an odd or even length, then a second pass to actually construct the new list. It might be simpler, though, to separate the two tasks.
doubleFromRight ls = zipWith ($) (cycle fs) ls -- [f0 ls0, f1 ls1, f2 ls2, ...]
where fs = if odd (length ls)
then [(*2), id]
else [id, (*2)]
So how does this work? First, we observe that to create the final result, we need to apply one of two function (id or (*2)) to each element of ls. zipWith can do that if we have a list of appropriate functions. The interesting part of its definition is basically
zipWith f (x:xs) (y:ys) = f x y : zipWith f xs ys
When f is ($), we're just applying a function from one list to the corresponding element in the other list.
We want to zip ls with an infinite alternating list of id and (*2). The question is, which function should that list start with? It should always end with (*2), so the starting item is determined by the length of ls. An odd-length requires us to start with (*2); an even one, id.
Most of the other solutions show you how to either use the building blocks you already have or building blocks available in the standard library to build your function. I think it's also instructive to see how you might build it from scratch, so in this answer I discuss one idea for that.
Here's the plan: we're going to walk all the way to the end of the list, then walk back to the front. We'll build our new list during our walk back from the end. The way we'll build it as we walk back is by alternating between (multiplicative) factors of 1 and 2, multiplying our current element by our current factor and then swapping factors for the next step. At the end we'll return both the final factor and the new list. So:
doubleFromRight_ :: Num a => [a] -> (a, [a])
doubleFromRight_ [] = (1, [])
doubleFromRight_ (x:xs) =
-- not at the end yet, keep walking
let (factor, xs') = doubleFromRight_ xs
-- on our way back to the front now
in (3-factor, factor*x:xs')
If you like, you can write a small wrapper that throws away the factor at the end.
doubleFromRight :: Num a => [a] -> [a]
doubleFromRight = snd . doubleFromRight_
In ghci:
> doubleFromRight [1..5]
[1,4,3,8,5]
> doubleFromRight [1..6]
[2,2,6,4,10,6]
Modern practice would be to hide the helper function doubleFromRight_ inside a where block in doubleFromRight; and since the slightly modified name doesn't actually tell you anything new, we'll use the community standard name internally. Those two changes might land you here:
doubleFromRight :: Num a => [a] -> [a]
doubleFromRight = snd . go where
go [] = (1, [])
go (x:xs) = let (factor, xs') = go xs in (3-factor, factor*x:xs')
An advanced Haskeller might then notice that go fits into the shape of a fold and write this:
doubleFromRight :: Num a => [a] -> [a]
doubleFromRight = snd . foldr (\x (factor, xs) -> (3-factor, factor*x:xs)) (1,[])
But I think it's perfectly fine in this case to stop one step earlier with the explicit recursion; it may even be more readable in this case!
If we really want to avoid calculating the length, we can define
doubleFromRight :: Num a => [a] -> [a]
doubleFromRight xs = zipWith ($)
(foldl' (\a _ -> drop 1 a) (cycle [(2*), id]) xs)
xs
This pairs up the input list with the cycled infinite list of functions, [(*2), id, (*2), id, .... ]. then it skips along them both. when the first list is finished, the second is in the appropriate state to be - again - applied, pairwise, - on the second! This time, for real.
So in effect it does measure the length (of course), it just doesn't count in integers but in the list elements so to speak.
If the length of the list is even, the first element will be doubled, otherwise the second, as you've specified in the question:
> doubleFromRight [1..4]
[2,2,6,4]
> doubleFromRight [1..5]
[1,4,3,8,5]
The foldl' function processes the list left-to-right. Its type is
foldl' :: (b -> a -> b) -> b -> [a] -> b
-- reducer_func acc xs result
Whenever you have to work on consecutive terms in a list, zip with a list comprehension is an easy way to go. It takes two lists and returns a list of tuples, so you can either zip the list with its tail or make it indexed. What i mean is
doubleFromRight :: [Int] -> [Int]
doubleFromRight ls = [if (odd i == oddness) then 2*x else x | (i,x) <- zip [1..] ls]
where
oddness = odd . length $ ls
This way you count every element, starting from 1 and if the index has the same parity as the last element in the list (both odd or both even), then you double the element, else you leave it as is.
I am not 100% sure this is more efficient, though, if anyone could point it out in the comments that would be great
So I m watching a very basic Tutorial, and I m at list comprehension where this comes up:
listx2 = [x * 2 | x<- numberList]
with numberList being a list of numbers
So this takes every number in the list and duplicates it, so numberList = [1,2] results in [2,4].
But HOW does the whole Syntax come together?
I know that x * 2 is the doubleing, but the rest just doesn't make sense to me.
| is the "or" Symbol as far as I know,and what does it do there?
x <- numberList gives x a number from the list, but why does it take just a number? and why so nicely one after the other? There is no recursion or anything that tells it to do one element at a time...
I learn stuff by understanding it, so is that even possible here or do I just have to accept this as "thats how it goes" and memorize the pattern?
List comprehensions use their own special syntax, which is
[ e | q1, q2, ..., qn ]
The | is not an "or", it's part of the syntax, just as [ and ].
Each qi can be of the following forms.
x <- list chooses x from the list
condition is a boolean expression, which discards the xs chosen before if the condition is false
let y = expression defines variable y accordingly
Finally, e is an expression which can involve all the variables defined in the qi, and which forms the elements in the resulting list.
What you see is syntactical sugar. So Haskell does not interpret the pipe (|) as a guard, etc. It sees the list comprehension as a whole.
This however does not mean that the <- are picked at random. Actually list comprehension maps nicely on the list monad. What you see is syntactical sugar for:
listx2 = do
x <- numberList
return x*2
Now a list type [] is actually a monad. It means that we have written:
listx2 = numberList >>= \x -> return (x*2)
Or even shorter:
listx2 = numberList >>= return . (*2)
Now the list monad is defined as:
instance Monad [] where
return x = [x]
xs >>= k = concat $ fmap k xs
So this means that it is equivalent to:
listx2 = numberList >>= return . (*2)
listx2 = concat (fmap (return . (*2)) numberList)
listx2 = concat (fmap (\x -> [2*x]) numberList)
Now for a list fmap is equal to map, so:
listx2 = concat $ map (\x -> [2*x]) numberList
listx2 = concatMap (\x -> [2*x]) numberList
so that means that for every element x in the numberList we will generate a singleton list [2*x] and concatenate all these singleton lists into the result.
I just started using Haskell and wanted to write a function that, given a list, returns a list in which every 2nd element has been doubled.
So far I've come up with this:
double_2nd :: [Int] -> [Int]
double_2nd [] = []
double_2nd (x:xs) = x : (2 * head xs) : double_2nd (tail xs)
Which works but I was wondering how you guys would write that function. Is there a more common/better way or does this look about right?
That's not bad, modulo the fixes suggested. Once you get more familiar with the base library you'll likely avoid explicit recursion in favor of some higher level functions, for example, you could create a list of functions where every other one is *2 and apply (zip) that list of functions to your list of numbers:
double = zipWith ($) (cycle [id,(*2)])
You can avoid "empty list" exceptions with some smart pattern matching.
double2nd (x:y:xs) = x : 2 * y : double2nd xs
double2nd a = a
this is simply syntax sugar for the following
double2nd xss = case xss of
x:y:xs -> x : 2 * y : double2nd xs
a -> a
the pattern matching is done in order, so xs will be matched against the pattern x:y:xs first. Then if that fails, the catch-all pattern a will succeed.
A little bit of necromancy, but I think that this method worked out very well for me and want to share:
double2nd n = zipWith (*) n (cycle [1,2])
zipWith takes a function and then applies that function across matching items in two lists (first item to first item, second item to second item, etc). The function is multiplication, and the zipped list is an endless cycle of 1s and 2s. zipWith (and all the zip variants) stops at the end of the shorter list.
Try it on an odd-length list:
Prelude> double_2nd [1]
[1,*** Exception: Prelude.head: empty list
And you can see the problem with your code. The 'head' and 'tail' are never a good idea.
For odd-lists or double_2nd [x] you can always add
double_2nd (x:xs) | length xs == 0 = [x]
| otherwise = x : (2 * head xs) : double_2nd (tail xs)
Thanks.
Here's a foldr-based solution.
bar :: Num a => [a] -> [a]
bar xs = foldr (\ x r f g -> f x (r g f))
(\ _ _ -> [])
xs
(:)
((:) . (*2))
Testing:
> bar [1..9]
[1,4,3,8,5,12,7,16,9]
I am having a very difficult time understand how to think about problems in a recursive way, and solve them using Haskell. I have spent hours of reading trying to wrap my head around recursion. The explanation I most often get from people who understand it is never clear and is something like "you pass a function, the name of the function as the argument, the function will then execute, solving a small piece of a the problem and calling the function again and again until you hit the base case".
Can someone please be kind enough, and walk me through the thought process of these three simple recursive functions? Not so much the functionality of them, but how the code, ends up executing and solving the problem, recursively.
Many thanks in advance!
Function 1
maximum' [] = error "maximum of empty list"
maximum' [x] = x
maximum' (x:rest) = max x(maximum' rest)
Function 2
take' n _
| n <= 0 = []
take' _ [] = []
take' n (x:xs) = x : take' (n-1) xs
Function 3
reverse' [] = []
reverse' (x:xs) = reverse' xs ++ [x]
Guidelines
When trying to understand recursion, you may find it easier to think about how the algorithm behaves for a given input. It's easy to get hung up on what the execution path looks like, so instead ask yourself questions like:
What happens if I pass an empty list?
What happens if I pass a list with one item?
What happens if I pass a list with many items?
Or, for recursion on numbers:
What happens if I pass a negative number?
What happens if I pass 0?
What happens if I pass a number greater than 0?
The structure of a recursive algorithm is often just a matter of covering the above cases. So let's see how your algorithms behave to get a feel for this approach:
maximum'
maximum [] = error
maximum [1] = 1
maximum [1, 2] = 2
As you can see, the only interesting behaviour is #3. The others just ensure the algorithm terminates. Looking at the definition,
maximum' (x:rest) = max x (maximum' rest)
Calling this with [1, 2] expands to:
maximum [1, 2] ~ max 1 (maximum' [2])
~ max 1 2
maximum' works by returning a number, which this case knows how to process recursively using max. Let's look at one more case:
maximum [0, 1, 2] ~ max 0 (maximum' [1, 2])
~ max 0 (max 1 2)
~ max 0 2
You can see how, for this input, the recursive call to maximum' in the first line is exactly the same as the previous example.
reverse'
reverse [] = []
reverse [1] = [1]
reverse [1, 2] = [2, 1]
Reverse works by taking the head of the given list and sticking it at the end. For an empty list, this involves no work, so that's the base case. So given the definition:
reverse' (x:xs) = reverse' xs ++ [x]
Let's do some substitution. Given that [x] is equivalent to x:[], you can see there are actually two values to deal with:
reverse' [1] ~ reverse' [] ++ 1
~ [] ++ 1
~ [1]
Easy enough. And for a two-element list:
reverse' [0, 1] ~ reverse' [1] ++ 0
~ [] ++ [1] ++ 0
~ [1, 0]
take'
This function introduces recursion over an integer argument as well as lists, so there are two base cases.
What happens if we take 0-or-less items? We don't need to take any items, so just return the empty list.
take' n _ | n <= 0 = []
take' -1 [1] = []
take' 0 [1] = []
What happens if we pass an empty list? There are no more items to take, so stop the recursion.
take' _ [] = []
take' 1 [] = []
take -1 [] = []
The meat of the algorithm is really about walking down the list, pulling apart the input list and decrementing the number of items to take until either of the above base cases stop the process.
take' n (x:xs) = x : take' (n-1) xs
So, in the case where the numeric base case is satisfied first, we stop before getting to the end of the list.
take' 1 [9, 8] ~ 9 : take (1-1) [8]
~ 9 : take 0 [8]
~ 9 : []
~ [9]
In the case where the list base case is satisfied first, we run out of items before the counter reaches 0, and just return what we can.
take' 3 [9, 8] ~ 9 : take (3-1) [8]
~ 9 : take 2 [8]
~ 9 : 8 : take 1 []
~ 9 : 8 : []
~ [9, 8]
Recursion is a strategy to apply a certain function to a set. You apply the function to the first element of that set, then you repeat the process to the remaining elements.
Let's take an example, you want to double all the integers inside a list. First, you think about which function should I use? Answer -> 2*, now you have to apply this function recursively. Let's call it apply_rec, so you have:
apply_rec (x:xs) = (2*x)
But this only changes the first element, you want to change all the elements on the set. So you have to apply the apply_rec to the remaining elements as well. Thus:
apply_rec (x:xs) = (2*x) : (apply_rec xs)
Now you have a different problem. When does apply_rec ends? It ends when you reach the end of the list. In other words [], so you need to cover this case as well.
apply_rec [] = []
apply_rec (x:xs) = (2*x) : (apply_rec xs)
When you reach the end you do not want to apply any function, hence the function apply_rec should "return" [].
Let's see the behavior of this function in a set = [1,2,3].
apply_rec [1,2,3] = (2 * 1) : (apply_rec [2,3])
apply_rec [2,3] = 2 : ((2 * 2) : (apply_rec [3]))
apply_rec [3] = 2 : (4 : ((2 * 3) : (apply_rec []))
apply_rec [] = 2 : (4 : (6 : [])))
resulting in [2,4,6].
Since you probably do not know very well recursion, the best thing is to start with simpler examples than those that you have presented. Take also a look learn recursion and at this Haskell Tutorial 3 - recursion.
You ask about "thought process", presumably of a programmer, not a computer, right? So here's my two cents:
The way to think about writing some function g with recursion is, imagine that you have already written that function. That's all.
That means you get to use it whenever you need it, and it "will do" whatever it is supposed to be doing. So just write down what that is - formulate the laws that it must obey, write down whatever you know about it. Say something about it.
Now, just saying g x = g x is not saying anything. Of course it is true, but it is a meaningless tautology. If we say g x = g (x+2) it is no longer a tautology, but meaningless anyway. We need to say something more sensible. For example,
g :: Integer -> Bool
g x | x<=0 = False
g 1 = True
g 2 = True
here we said something. Also,
g x = x == y+z where
y = head [y | y<-[x-1,x-2..], g y] -- biggest y<x that g y
z = head [z | z<-[y-1,y-2..], g z] -- biggest z<y that g z
Have we said everything we had to say about x? Whether we did or didn't, we said it about any x there can be. And that concludes our recursive definition - as soon as all the possibilities are exhausted, we're done.
But what about termination? We want to get some result from our function, we want it to finish its work. That means, when we use it to calculate x, we need to make sure we use it recursively with some y that's defined "before" x, that is "closer" to one of the simplest defined cases we have.
And here, we did. Now we can marvel at our handiwork, with
filter g [0..]
Last thing is, in order to understand a definition, don't try to retrace its steps. Just read the equations themselves. If we were presented with the above definition for g, we'd read it simply as: g is a Boolean function of a number which is True for 1, and 2, and for any x > 2 that is a sum of its two preceding g numbers.
Maybe the way your are presenting your issue is not the good one, I mean this is not by studding implementation of existing recursive function that you will understand how you can replicate it. I prefer to provide you an alternative way, it could be view as a methodical process which help you yo write standard skeleton of recursive call and then facilitate reasoning about them.
All your example are about list, then the first stuff when you work with list is to be exhaustive, I mean to use pattern matching.
rec_fun [] = -- something here, surely the base case
rec_fun (x:xs) = -- another thing here, surely the general case
Now, the base case could not include recursive otherwise you will surely end up with a infinite loop, then the base case should return a value, and the best way to grasp this value is to look to the type annotation of your function.
For example :
reverse :: [a] -> [a]
Could encourage you to consider the base case as a value of type [a], as [] for reverse
maximum :: [a] -> a
Could encourage you to consider the base case as a value of type a for maximum
Now for the recursive part, as said the function should include a call of herself.
rec_fun (x:xs) = fun x rec_fun xs
with fun to denote the use of another function which are responsible to realize the chaining of recursive call. To help your intuition we can present it as an operator.
rec_fun (x:xs) = x `fun` rec_fun xs
Now considering (again) the type annotation of your function (or more shortly the base case), you should be able to deduce the nature of this operator. For reverse, as its should return a list the operator is surely the concatenation (++) and so on.
If you put all this stuff together, it shouldn't be so hard to end up with the desired implementation.
Of course, as with any other algorithm, you will always need to thinks a little bit and there are no magical recipe, you must think. For example, when you know the maximum of the tail of the list, what is the maximum of the list ?
Looking at Function 3:
reverse' [] = []
reverse' (x:xs) = reverse' xs ++ [x]
Let's say you called reverse' [1,2,3] then...
1. reverse' [1,2,3] = reverse' [2,3] ++ [1]
reverse' [2,3] = reverse' [3] ++ [2] ... so replacing in equation 1, we get:
2. reverse' [1,2,3] = reverse' [3] ++ [2] ++ [1]
reverse' [3] = [3] and there is no xs ...
** UPDATE ** There *is* an xs! The xs of [3] is [], the empty list.
We can confirm that in GHCi like this:
Prelude> let (x:xs) = [3]
Prelude> xs
[]
So, actually, reverse' [3] = reverse' [] ++ [3]
Replacing in equation 2, we get:
3. reverse' [1,2,3] = reverse' [] ++ [3] ++ [2] ++ [1]
Which brings us to the base case: reverse' [] = []
Replacing in equation 3, we get:
4. reverse' [1,2,3] = [] ++ [3] ++ [2] ++ [1], which collapses to:
5. reverse' [1,2,3] = [3,2,1], which, hopefully, is what you intended!
Maybe you can try to do something similar with the other two. Choose small parameters. Have success!
I too have always found it hard to think recursively. Going through the http://learnyouahaskell.com/ recursion chapter a few times, then trying to re-implement his re-implementations has helped solidify it for me. Also, generally, learning to program functionally by carefully going through the Mostly Adequate Guide and practicing currying and composition has made me focus on solving the core of the problem then applying it in other ways.
Back to recursion...Basically these are the steps I go through when thinking of a recursive solution:
The recursion has to stop, so think of one or more base cases. These are the case(s) where further calls to the function are no longer necessary.
Think of the simplest non-base case (the recursive case), and think of how you can call the function again in a way that will result in the base case...so that the function doesn't keep calling itself. The key is focusing on the simplest non-base case. That will help your mind wrap around the problem.
So, for example, if you have to reverse a list, the base case would be an empty list or a list of one element. When moving to the recursive case, don't think about [1,2,3,4]. Instead think of the simplest case ([1,2]) and how to solve that problem. The answer is easy: take the tail and append the head to get the reverse.
I'm no haskell expert...I just started learning myself. I started with this which works.
reverse' l
| lenL == 1 || lenL == 0 = l
where lenL = length l
reverse' xs ++ [x]
The guard checks if it's a 1 or 0 length list and returns the original list if it is.
The recursive case happens when the list is not length 0 or 1 and gets the reverse of the tail, appending the head. This happens until the list is 1 or 0 length and you have your answer.
Then I realized you don't need the check for a singleton list, since the tail of a one element list is an empty list and I went to this which is the answer in learnyouahaskell:
reverse' :: [a] -> [a]
reverse' [] = []
reverse' (x:xs) = reverse' xs ++ [x]
I hope that helps. At the end of the day, practice makes perfect, so keep trying to solve some things recursively and you'll get it.