I started to play a bit with Haskell and came across the following implementation of the sum function:
sum [] = 0
sum (x:xs) = x + sum xs
And then there's an explanation that shows how the function would behave on a real example:
sum [1,2,3]
1 + (sum [2,3])
1 + (2 + sum [3])
1 + (2 + (3 + sum []))
1 + (2 + (3 + 0))
= 6
I don't understand, why every time sum [x] is called, the list gets smaller by 1 element?
My only assumption is that when the construction (x:xs) is executed, then the element x of the list, not only is retrieved, but also removed (similar to the stacks pop() method.), but I am not sure about this.
In the notation x:xs, x is the head of the list, which is 1 item, and xs is the tail of the list, which is a list of 0 or more items.
Since the recursive call is on xs, the problem size set gets reduced by 1 with each level of recursion.
There's no such a thing as "removing an element from a list". Lists are immutable, just like any other object. Now, with regards to the implementation, in:
sum (x:xs) = x + sum xs
you are pattern matching a list into it's head x and the rest of the list (without the head) xs. Specifically, in sum [1, 2, 3], then you would get:
sum (1:[2, 3]) = 1 + sum [2, 3]
If you remember, (:) is used to append an element to a list. So: 1:[2, 3] is actually [1, 2, 3] which can also be written as: 1:2:3:[].
The only thing that you should remember is that pattern matching on (x:xs), means: put the head of a list in x and the rest of the list in xs.
It's recursion
Basically, you're calling the function again with the rest of the list summed with the first element.
Related
Reading the book Get Programming with Haskell, one of the questions was to find if a given element is in the first half of a list. This can be done as
isInFirstHalf x xs = elem x firstHalf
where firstHalf = take (length xs `div` 2) xs
However, the problem is that here length traverses the whole list. In an imperative language, one can shortcircut the loop early by keeping track of the element index and the current counter. E.g. if the list has a million elements, and there was a match on the third element, once you finish looping through the sixth element, you can immediately return true.
My question is if there's a way to implement something like this in Haskell.
Sure.
halfAsLong (x:_:xs) = x:halfAsLong xs
halfAsLong _ = []
isInFirstHalf x xs = elem x (zipWith const xs (halfAsLong xs))
Try it out:
> isInFirstHalf 3 (1:2:3:4:5:6:undefined)
True
Exercises for the reader:
Where did the element index and current counter of your proposed imperative solution go? (They are still in there, just hidden in a way I think is a bit subtle!)
This rounds down when dividing odd lengths in half, like length xs `div` 2 does. How would the code have to change to round up, like (length xs + 1) `div` 2 does?
Daniel Wagner posted a very nice answer that shows that you don't really need indices, after all.
Still, if you do want to use indices, a solution can be crafted as follows.
We enumerate all the list elements by pairing them with their indices. This is done by using zip [0..] xs (or zip [1..] xs if you want to start counting at 1).
We find whether your x is in the list, and find its index i if it's present. One could proceed by direct recursion, or use something like dropWhile ((/= x) . fst) ... and then test the result.
Once we know i, we need to check whether there are at least i elements after that. This can be solved by direct recursion, or by dropping i-1 elements and testing whether the result is a non empty list.
There are other alternatives, of course. We could for instance skip enumerating elements with zip [0..] and use recursion by keeping track of the current index: foo n x (y:ys) = ... foo (n+1) x ys ....
Here’s another way to think of the task. An element x appears in the first half of a list xs, excluding the midpoint, if there are strictly fewer elements before the first occurrence of the element than after it.
We can write break (== x) xs using the standard function break :: (a -> Bool) -> [a] -> ([a], [a]) to split xs into two parts: those appearing before x (or all of xs, if x is not found), and the remainder (including x, if it is found).
> break (== 0) []
([], [])
> break (== 0) [0, 1]
([], [0, 1])
> break (== 0) [1, 0]
([1], [0])
> break (== 0) [1, 2, 0, 3, 4]
([1, 2], [0, 3, 4])
> break (== 0) [1, 2, 3, 4]
([1, 2, 3, 4], [])
We then want to compare the lengths of these two parts without calculating the actual lengths strictly as Int. To do so, we can compute the shape of each part by ignoring all its elements, using shape = map (const ()), a.k.a. void :: (Functor f) => f a -> f () specialised to lists.
shape :: [a] -> [()]
shape = void
The Ord instance for lists sorts them lexicographically, and all values of type () are equal—okay, the only value of type ()—so a comparison of shapes [()] is a comparison of the lengths of the lists, which is also lazy enough for our purposes. (For maximal laziness, shape could be defined as genericLength on a lazy natural number type like data N = Z | S N with an appropriate Ord instance.)
> [] < repeat ()
True
> shape [5 .. 10] >= shape [1 .. 3]
True
> shape [1 .. 3] > shape [1 ..]
False
We can also “decrement” the shape of a list using drop 1, which we’ll use to skip counting the element itself if it was found. (Alternatively, we could “increment” the shape with (() :).)
Finally, putting these elements together leads to a fairly simple solution:
isInFirstHalf :: (Eq a) => a -> [a] -> Bool
isInFirstHalf x xs = shape before < shape (drop 1 after)
where
(before, after) = break (== x) xs
Notice that if the element was not found, after will be empty, so drop 1 will have no effect, but the shape of before can’t possibly be smaller than the empty shape [], so the comparison (<) will still correctly return False.
I'm working on an assignment to calculate the sum of all integers in a list. I am supposed to do so without help from any standard library functions other than the standard addition operator.
I assume this means I cannot use length. I'm understanding that correct, right? This becomes and issue as I'm not sure how I'd know when to stop my recursive function to iterate through the array.
The input's a should be expected to deal with are [] and [0-X] where x is any integer. The example has X as 10, so don't expect anything huge to be tested.
The assignment mentioned it should be in the following format, but I'm not sure I follow:
sum1 [] = ...
sum1 (x:xs) = ...
Here's what I have utilizing length. It works correctly, and I don't really care if it's inefficient. It's my first time using Haskell:
iterate_list :: [Int] -> Int -> Int -> IO()
iterate_list func_list index total = do
if index < length func_list
then do
let new_total = total + (func_list !! index)
let new_index = index + 1
iterate_list func_list new_index new_total
else
print(total)
sum1 :: [Int] -> IO()
sum1 list = do
if length list < 1
then do
print(0)
else
iterate_list list 0 0
update: Based on comments, here is the code I've produced.
total :: Int
total = 0
sum1 :: [Int] -> IO()
sum1 (x:xs) = do
if xs == []
then do
print(total)
else do
let total = total + x
sum1 xs
However, the issue I'm having now is total returns 0, almost like it's a constant. I might be programming it that way, but I'm not too sure what's going on.
Based on the assignment description, I cannot pass a variable through the recursive function to store this value. I've done it that way before. Does anyone know if there is a way to have a "total" variable outside of the function.
total :: Int
total = 0
sum1 :: [Int] -> IO()
sum1 (x:xs) = do
if xs == []
then do
print(total)
else do
let total = total + x
sum1 xs
What this code says:
The global total is a constant integer, equal to 0
sum1 takes a list of integers and produces an IO action that produces no result
If sum1 is given a non-empty list, then:
If the tail of that list is empty (i.e., the whole list has 1 element), then print the global variable total
Otherwise:
Create a new local variable named total, hiding the global one, and define it as x plus itself (an infinite loop)
Recursively call sum1 on the tail of the list
If sum1 is given an empty list, it will throw an error
This shows that you’re thinking very imperatively. Rather than trying to define a bottom-up procedure for updating the total incrementally until it builds up to the final result, you need to think in terms of how to compute the total as a value by breaking down the input. Variables in Haskell are immutable; when you write =, it means equal, never “assign” or “update”.
First, sum1 should return Int because you don’t need IO or do notation for this.
sum1 :: [Int] -> Int
If you want to print the result of sum1 applied to some list someList (for example from main), use print there, i.e., print (sum1 someList).
Next, the function should be defined in terms of the the two possible cases of the input: an empty list and a non-empty list.
sum1 [] = …
sum1 (x : xs) = …
You need to define these cases so that an input like sum1 [1, 2, 3, 4], which you’ll recall is syntactic sugar for sum1 (1 : (2 : (3 : (4 : [])))) produces something equivalent to 1 + 2 + 3 + 4.
First, in the case of an empty list, what should the result be? You can deduce this from the fact that the sum of two lists appended together should be the same as the sum of each of them separately; that is, for any lists xs and ys, these expressions should produce the same result:
sum1 xs + sum1 ys
sum1 (xs ++ ys)
Supposing xs or ys is empty, it should not change the sum:
sum1 [] + sum1 ys = sum1 ([] ++ ys) = sum1 ys
sum1 xs + sum1 [] = sum1 (xs ++ []) = sum1 xs
Second, as for the non-empty case: you’re given an element x :: Int and a list xs :: [Int], and you need to compute the total of the two. For example, given [1, 2, 3, 4], x is set to 1 and xs is [2, 3, 4]. Suppose you had the sum of xs already; what is the result in terms of that and x? And how can you obtain the sum of xs?
You cannot simply update a variable in Haskell. All values are immutable. You should be thinking in terms of how to use the return value of a recursive call, not simply calling a function for its side effect.
The hint from your original question was to define
sum [] = ...
sum (x:xs) = ...
First, what is the sum of the non-empty list? It must include x, so you'll be adding something to x:
sum (x:xs) = x + ...
Second, what is the sum of an empty list? While it might not make sense to even define a value for an empty list, think about what sum [3] must surely return, and the fact that sum (3:[]) == 3 + .... There's a rather simple definition for sum [] that is almost dictated by the definition of addition.
sum :: [Int] -> Int
sum [] = 0
sum (x:xs) = x + sum xs
I do not understand what the purpose of the line sum [] = 0 is. I found this piece of code in a textbook (it did not go into detail as to what this line does.)
sum [] = 0 is the edge condition of the recursion.
Suppose we have sum [1, 4, 6, 8]. The list can be rewritten as 1:4:6:8:[]. The empty list is the last 'element'. The calculation is as follow (1 + ( 4 + (6 + ( 8 + 0)))). When all the elements of the list have been traversed, what remains is the empty list. Adds zero to the calculated result and ends the iteration.
I am exercising for a final exam tomorrow. I am trying a couple of weird examples. For example, I am given a list of sublists like this: [[1, 2], [2, 3, 4], [5, 6], [7, 8], [8, 9, 10]]. I want to add the second and third sublists together and return their sum by using a list comprehension. I have tried numerous things, but I am not able to succeed.
I realise that the list comprehension generates a cons pair of each of my sublists and tries to add the second and the third elements of each cons pair. But this is not what I want. I want to output [20], because 2+3+4+5+6 = 20.
I wrote this, where I am trying to only add the second sublist in a cons pair. But then there is no way to also generate the third sublist. So I am kind of stuck.:
sumTwoThree::[[Int]]->[Int]
sumTwoThree list = [(x + xs) | (x:xs)<-(list!!1)]
I also wrote this:
sumTwoThree::[[Int]]->[Int]
sumTwoThree list = [head xs + head (tail xs) | (x:xs)<-list, (length xs > 1)]
but this only generates the sublists that have at least 3 elements and then it adds together the 2nd and 3rd elements of those sublists.
Basically, you want to filter out any sublist that isn't the second or third, then include them in the result. After that, you use sum. Like so:
sumTwoThree xs = sum [x | (i, sub) <- zip [1,2..] xs,
i == 2 || i == 3,
x <- sub]
You cannot accomplish this without using the sum function. This is because a list comprehension is just syntactic sugar for using the list monad. And you have to fold over a list to compute the sum of its elements.
If you want to really get a good idea about what a list comprehension is, then learn about the list monad, and even try to understand how this works:
foo [] = [[]]
foo (x:xs) = [x':xs' | x' <- x, xs' <- foo xs]
Then observe what it does:
Main*> foo ["123", "abc"]
["1a","1b","1c","2a","2b","2c","3a","3b","3c"]
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.