Related
Trying to double elements of a list that are greater than 5 for example.
to double every element in a list i would do this
doubleAll n = [2*x| x <-n]
now i want to double all elements in list that are greater than 5 using list comprehensions.
So if i do this
doubleAll n = [2*x| x <-n, x>5]
My list [1,2,3,4,5] would result in to [10]. But i want my list to show [1,2,3,4,10]
Can anyone explain what i did wrong and how can this be fixed?
An interpretation of [2*x| x <-n, x>5] is:
Take the next element from n and call it x
Proceed if x>5, otherwise go to step 1
Return the value 2*x as the next element of the list.
Repeat
From this it is clear that the x>5 filters out elements of n. The expression is equivalent to:
map (\x -> 2*x) ( filter (\x -> x>5) n )
As Arthur mentioned, you want something like:
[ if x > 5 then 2*x else x | x <- n ]
It's interpretation is:
Take the next value of n and call it x
Return the value if x > 5 then 2*x else x as then next value of the list.
This is clearer to understand if you don't use list comprehensions and use the map and filter operations instead:
-- Apply a function to every element of the list.
map :: (a -> b) -> [a] -> [b]
-- Throw out list elements that don't pass the test.
filter :: (a -> Bool) -> [a] -> [a]
Your original doubleAll is equivalent this:
-- Multiply every element of the list by two.
doubleAll xs = map (*2) xs
The version where you double only if x > 5 would be this:
-- Apply the `step` function to every element of the list. This step function
-- multiplies by two if x >= 5, otherwise it just returns its argument.
doubleAll xs = map step xs
where step x | x >= 5 = 2*x
| otherwise = x
The problem with the list comprehension version that you wrote is that it's instead equivalent to this:
-- Filter out list elements that are smaller than 5, then double the remaining ones.
doubleAll xs = map (*2) (filter (>=5) xs)
The list comprehension solution that produces the result you want would instead be this:
doubleAll xs = [if x >= 5 then x*2 else x | x <- xs]
As a more general remark, I always recommend to newcomers to stay away from list comprehensions and learn the higher-order list functions, which are more general and less magical.
So i've got this function to swap pairs of numbers in haskell, and i don't know what i've done wrong, maybe you guys can give me a hand.
SO basically this function gets a list, say, [1,2,3,4,5], and returns the numbers swapped by pairs, something like, [2,1,4,3,5]. if the number of elements is odd, the last element stays the same.
Here's what i've done:
swapPairs :: [a] -> [a]
swapPairs (x:xs) = [!!x = !!x+1 && !!x+1 = !!x| x <- xs]
-- Return first two elements in inverted order, recusively call for remaining list,
-- only matches lists of two or more elements
swapPairs (a:b:xs) = b : a : swapPairs xs
-- Return tail for zero or one remaining elements
swapPairs (xs) = xs
You can use pattern matching to fetch 2 head elements:
swapPairs (x:y:xs) = y : x : (swapPairs xs)
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.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Split list and make sum from sublist?
Im trying to solve this problem.
I need to do a sum of elements from a list which are separated from each other only with "0".
So for example I can have something like this as input: [1,2,3,0,3,4,0,2,1]
and the output should be [6,7,3].
So far I managed to do something like this:
cut (x:xs) | x > 0 = x : (cut xs)
| otherwise = []
first (xs) = ( (foldl (+) 0 (cut (xs))) ) : []
second (xs) = ( (foldl (+) 0 (cut (reverse (xs)))) ) : []
test (xs) = first(xs) ++ second(xs)
Problem is that this only works with only 1 instance of "0" in my list.
I was trying to solve this by editing my cut function:
cut [] = []
cut (x:xs) | x > 0 = foldl (+) 0 ( x : cut xs) : []
| x == 0 = (cut xs)
But I cant figure out how to adjust it, so it will separate the sums. Right now it just throws the sum of all the elements as the output.
You can divide your problem into two tasks
Split a list into parts on zeros.
Sum parts.
For the first task we have Data.List.Split module which exports splitOn function.
It does precisely what we need:
> splitOn [1] [0,0,0,1,0,0,0,1,0]
[[0,0,0],[0,0,0],[0]]
For the second task there is well-known map-function which applies a function to the each element of the list.
In our case this function is sum:
> map sum [[1,2,3],[4,5,6],[7,8,9]]
[6,15,24]
So:
> :m +Data.List.Split
> map sum . splitOn [0] $ [1,2,3,0,3,4,0,2,1]
[6,7,3]
For homework you should definitely follow dave's answer. However, here is a more advanced solution, employing groupBy as poor man's split:
import Data.List (groupBy)
map sum $ groupBy (const (/=0)) list
This might look cute, but note that there are still the zeros at the beginning of the sub-lists present, so you can't use this solution without changes if that matters (e.g if you need products instead of sums)
[Explanation]
groupBy looks if the first element of the current group "fits together" with the current element of the list. In that case the current element will be added to the group, else a new group starts. E.g.
groupBy (\x y -> x `mod` y == 0) [81,3,9,25,5]
--[[81,3,9],[25,5]]
Here the test ist successful for 81 'mod' 3 and 81 'mod' 9, but not for 81 'mod' 25, which starts a new group. Again, 25 'mod' 5 is successful.
But in our case all elements "fit" in the current group as long as they are not 0, so we don't even have to look at the first element. And if a 0 is found, a new group is started.
const (/=0) means just \_ y -> y /= 0, so regardless what the first argument is, it just tests that the second element isn't 0. To see why, look at the definition:
const :: a -> b -> a
const a _ = a
Now our lambda can be written as
\x y -> const (/= 0) x y
As from the const call only the first of the two arguments "survives", we have
\x y -> (/= 0) y
... or...
\_ y -> y /= 0
Even if you're unable to install to install the split package and use Data.List.Split as Matvey suggests, you can still use the general approach:
Split the weird list with 0 separators into a more conventional list of lists.
Sum each list.
So
yourFunction = map sum . split
Now we have to write split.
split :: [Int] -> [[Int]]
In general, when we want to pull a list apart to synthesise something new, we need to use a fold.
split = foldr cons nil where
nil here should be whatever you want split [] to be.
nil = --TODO: exercise for you; clue: NOT []
cons meanwhile combines one of your numbers, with the answer from the previous step of the fold. Obviously, you'll need to do different things depending on whether or not the number is 0.
cons 0 xss = --TODO
cons x (xs : xss) = --TODO; why will this pattern match never fail?
im searching for a solution for my Haskell class.
I have a list of numbers and i need to return SUM for every part of list. Parts are divided by 0. I need to use FOLDL function.
Example:
initial list: [1,2,3,0,3,4,0,5,2,1]
sublist [[1,2,3],[3,4],[5,2,1]]
result [6,7,7]
I have a function for finding 0 in initial list:
findPos list = [index+1 | (index, e) <- zip [0..] list, e == 0]
(returns [4,6] for initial list from example)
and function for making SUM with FOLDL:
sumList list = foldl (+) 0 list
But I completely failed to put it together :/
---- MY SOLUTION
In the end I found something completely different that you guys suggested.
Took me whole day to make it :/
groups :: [Int] -> [Int]
groups list = [sum x | x <- makelist list]
makelist :: [Int] -> [[Int]]
makelist xs = reverse (foldl (\acc x -> zero x acc) [[]] xs)
zero :: Int -> [[Int]] -> [[Int]]
zero x acc | x == 0 = addnewtolist acc
| otherwise = addtolist x acc
addtolist :: Int -> [[Int]] -> [[Int]]
addtolist i listlist = (i : (head listlist)) : (drop 1 listlist)
addnewtolist :: [[Int]] -> [[Int]]
addnewtolist listlist = [] : listlist
I'm going to give you some hints, rather than a complete solution, since this sounds like it may be a homework assignment.
I like the breakdown of steps you've suggested. For the first step (going from a list of numbers with zero markers to a list of lists), I suggest doing an explicit recursion; try this for a template:
splits [] = {- ... -}
splits (0:xs) = {- ... -}
splits (x:xs) = {- ... -}
You can also abuse groupBy if you're careful.
For the second step, it looks like you're almost there; the last step you need is to take a look at the map :: (a -> b) -> ([a] -> [b]) function, which takes a normal function and runs it on each element of a list.
As a bonus exercise, you might want to think about how you might do the whole thing in one shot as a single fold. It's possible -- and even not too difficult, if you track through what the types of the various arguments to foldr/foldl would have to be!
Additions since the question changed:
Since it looks like you've worked out a solution, I now feel comfortable giving some spoilers. =)
I suggested two possible implementations; one that goes step-by-step, as you suggested, and another that goes all at once. The step-by-step one could look like this:
splits [] = []
splits (0:xs) = [] : splits xs
splits (x:xs) = case splits xs of
[] -> [[x]]
(ys:yss) -> ((x:ys):yss)
groups' = map sum . splits
Or like this:
splits' = groupBy (\x y -> y /= 0)
groups'' = map sum . splits'
The all-at-once version might look like this:
accumulate 0 xs = 0:xs
accumulate n (x:xs) = (n+x):xs
groups''' = foldr accumulate [0]
To check that you understand these, here are a few exercises you might like to try:
What do splits and splits' do with [1,2,3,0,4,5]? [1,2,0,3,4,0]? [0]? []? Check your predictions in ghci.
Predict what each of the four versions of groups (including yours) output for inputs like [] or [1,2,0,3,4,0], and then test your prediction in ghci.
Modify groups''' to exhibit the behavior of one of the other implementations.
Modify groups''' to use foldl instead of foldr.
Now that you've completed the problem on your own, I am showing you a slightly less verbose version. Foldr seems better in my opinion to this problem*, but because you asked for foldl I will show you my solution using both functions.
Also, your example appears to be incorrect, the sum of [5,2,1] is 8, not 7.
The foldr version.
makelist' l = foldr (\x (n:ns) -> if x == 0 then 0:(n:ns) else (x + n):ns) [0] l
In this version, we traverse the list, if the current element (x) is a 0, we add a new element to the accumulator list (n:ns). Otherwise, we add the value of the current element to the value of the front element of the accumulator, and replace the front value of the accumulator with this value.
Step by step:
acc = [0], x = 1. Result is [0+1]
acc = [1], x = 2. Result is [1+2]
acc = [3], x = 5. Result is [3+5]
acc = [8], x = 0. Result is 0:[8]
acc = [0,8], x = 4. Result is [0+4,8]
acc = [4,8], x = 3. Result is [4+3,8]
acc = [7,8], x = 0. Result is 0:[7,8]
acc = [0,7,8], x = 3. Result is [0+3,7,8]
acc = [3,7,8], x = 2. Result is [3+2,7,8]
acc = [5,7,8], x = 1. Result is [5+1,7,8] = [6,7,8]
There you have it!
And the foldl version. Works similarly as above, but produces a reversed list, hence the use of reverse at the beginning of this function to unreverse the list.
makelist l = reverse $ foldl (\(n:ns) x -> if x == 0 then 0:(n:ns) else (x + n):ns) [0] l
*Folding the list from the right allows the cons (:) function to be used naturally, using my method with a left fold produces a reversed list. (There is likely a simpler way to do the left fold version that I did not think of that eliminates this triviality.)
As you already solved it, another version:
subListSums list = reverse $ foldl subSum [0] list where
subSum xs 0 = 0 : xs
subSum (x:xs) n = (x+n) : xs
(Assuming that you have only non-negative numbers in the list)