I am new to Haskell and I came across one thing that I can seem to come around.So I have this function:
merge :: [Int] -> [Int]
merge xs = merged ++ padding
where padding = replicate (length xs - length merged) 0
merged = combine (filter (/= 0) xs)
combine (x:y:xs) | x == y = x * 2 : combine xs
| otherwise = x : combine (y:xs)
combine x = x
The problem is that I can't quite grasp what combine does.I did my research and found that
myFunction(x:xs) ...
represents that "x" is somehow the head of my list,and I can do stuff with it,right?Does that mean that in myFunction(x:y:xs) ...
"x" is the last element and "y" would be the second to the last element in xs?Is this right or am I terribly wrong?Also what about the ":" after "| x == y = x * 2",I learned that in Haskell ":" means appending a value to a list,but in this context I really can't quite understand what it does...Some help would be much apreciated.
x:y:xs is a pattern that says, "This is a list with at least 2 elements.We will call the first and second elements of this list x and y. The remaining sublist, which we will call xs may be empty or non-empty". That is, it represents both the list [1,2] and [1,2,3,4.....] but not [1].
Your second query can be answered by rewriting
| x == y = x * 2 : combine xs
as
| (x == y) = ((x * 2) : combine xs) for clarity. This is a standard if-else flow, except that Haskell does not require you to put those parentheses explicitly. Note that the 'pipes' are called guards and work similar to a switch-case statement in Java/C#.
What is the more haskellish way to stop the recursion of this function? Currently I'm using a nested if/else, and returning an empty list if the next combination "overflows".
nextcomb [] [] = []
nextcomb lst maxes | length lst == length maxes =
let lastel = last lst
in if lastel < last maxes
then (init lst) ++ [lastel+1]
else let higherbit = (nextcomb (init lst) (init maxes))
in if higherbit == []
then []
else higherbit ++ [1]
nextcomb lst maxes | otherwise = []
To clarify, what it does is it takes a list of numbers like [1,1,1,1] and increments it like:
[1,1,1,1] -> [1,1,1,2]
...
[1,1,1,9] -> [1,1,2,1]
...
[1,1,9,9] -> [1,2,1,1]
etc.
BUT, the second argument is a list that indicates the maxmum value for each column. So if the maxes were [2,3], and the initial list was [1,1], then the progression woudld be:
[1,1] -> [1,2]
[1,2] -> [1,3]
[1,3] -> [2,1]
[2,1] -> [2,2]
[2,2] -> [2,3]
[2,3] -> []
Edit: "Little Endian" version as recommended by chepner
nextcomb' [] [] = []
nextcomb' lst maxes | length lst /= length maxes = []
nextcomb' lst maxes =
let firstel = head lst
in if firstel < head maxes
then (firstel+1) : (tail lst)
else let higherbit = (nextcomb' (tail lst) (tail maxes))
in if higherbit == []
then []
else 1 : higherbit
You should make illegal states unrepresentable
So, instead of using two lists, use a list of tuples. For example, the first value in each tuple could be the maximum, the second one the actual value.
This also simplifies the logic dramatically, as the errors "maxes too long" and "maxes too short" can not happen.
Your if expression is simply hiding the real base case, which is that if either argument is empty, return the empty list.
nextcomb [] [] = []
nextcomb lst maxes | length lst != length maxes = []
nextcomb lst maxes = let lastel = last lst
in if lastel < last maxes
then (init lst) ++ [lastel+1]
else let higherbit = (nextcomb (init lst) (init maxes))
in if higherbit == []
then []
else higherbit ++ [1]
I would probably rework the logic like this. (Note, I'm far from a Haskell expert and tend to answer these questions as an exercise for myself :)
-- Reversing the arguments and the ultimate return value
-- lets you work with the head of each list, rather than the last
-- element
nextcomb lst maxes = reverse $ nextcomb' (reverse lst) (reverse maxes)
-- The real work. The base case is two empty lists
nextcomb' [] [] = []
-- If one list runs out before the other, it's an error. I think
-- it's faster to check if one argument is empty when the other is not
-- than to check the length of each at each level of recursion.
nextcomb' [] _ = error "maxes too long"
nextcomb' _ [] = error "maxes too short"
-- Otherwise, it's just a matter of handling the least-significant
-- bit correctly. Either abort, increment, or reset and recurse
nextcomb' (x:xs) (m:ms) | x > m = error "digit too large"
| x < m = (x+1):xs -- just increment
| otherwise = 0:(nextcomb' xs ms) -- reset and recurse
(Actually, note that nextcomb' [] _ won't trigger if you don't recurse after the last digit. You could argue that a too-long maxes isn't a big deal. I'll leave this unfixed, as the next part handles it correctly.)
Alternately, you could verify the lengths match in the initial call; then you can assume that both will become empty at the same time.
nextcomb lst maxes | length lst == length maxes = reverse $ nextcomb' (reverse lst) (reverse maxes)
| otherwise = error "length mixmatch"
nextcomb' [] [] = []
nextcomb' (x:xs) (m:ms) | x > m = error "digit too large"
| x < m = (x+1):xs
| otherwise = 0:(nextcomb' xs ms)
Here's an example using Either to report errors. I won't vouch for the design other than to say it does type check and run. It's not too different from the previous code; it just uses <$> to lift reverse and (0:) to work with arguments of type Either String [a] instead of arguments of type [a].
import Control.Applicative
nextcombE lst maxes = reverse <$> nextcombE' (reverse lst) (reverse maxes)
nextcombE' [] [] = Right []
nextcombE' [] _ = Left "maxes too long"
nextcombE' _ [] = Left "maxes too short"
nextcombE' (x:xs) (m:ms) | x > m = Left "digit too large"
| x < m = Right ((x+1):xs)
| otherwise = (0:) <$> (nextcombE' xs ms)
Please check if next implementation is useful for you, because a more "haskellish" way (at least for me), is using built in recursive functions to achieve the same goal
nextcomb [] [] = []
nextcomb lst maxes
| length lst /= length maxes = []
| lst == maxes = []
| otherwise = fst $ foldr f ([],True) $ zip lst maxes
where
f (l,m) (acc, mustGrow)
| mustGrow && l < m = (l + 1:acc, False)
| mustGrow = (1:acc, True)
| otherwise = (l:acc, False)
(Edited) If need catch errors then can try this:
nextcomb [] _ = Left "Initial is empty"
nextcomb _ [] = Left "Maximus size are empty"
nextcomb lst maxes
| length lst /= length maxes = Left "List must be same length"
| lst == maxes = Left "Initial already reach the limit given by Maximus"
| otherwise = Right $ fst $ foldr f ([],True) $ zip lst maxes
where
f (l,m) (acc, mustGrow)
| mustGrow && l < m = (l + 1:acc, False)
| mustGrow = (1:acc, True)
| otherwise = (l:acc, False)
Let's draw a diagram! I'm going to make slightly different assumptions than the initial problem:
A little-endian representation like chepner suggested;
Instead of inclusive maximum values, I'm going to go with exclusive bases to make things more similar to addition-with-carry.
I'm going to use digits in the range [0, base).
Here's the diagram:
digits = [d0, d1, ..., dn]
bases = [b0, b1, ..., bn]
--------------------------
result = [r0, r1, ..., rn]
Now we can ask: for each digit ri of the result, what does its value depend on? Well, these things:
The value of di
The value of bi
Whether the previous r resulted in a carry
So we can write this as a function:
import Control.Monad.State -- gonna use this a bit later
type Base = Int
type Digit = Int
type Carry = Bool
-- | Increment a single digit, given all the contextual information.
singleDigit' :: Base -> Digit -> Carry -> (Digit, Carry)
singleDigit' base digit carry = (digit', carry')
where sum = digit + if carry then 1 else 0
digit' = if sum < base then sum else sum - base
carry' = base <= sum
Note that I took care to make sure that the singleDigit' function's type ends with Carry -> (Digit, Carry). This is because that fits the state -> (result, state) pattern that is typical of the state monad:
-- | Wrap the `singleDigit'` function into the state monad.
singleDigit :: Base -> Digit -> State Carry Digit
singleDigit base digit = state (singleDigit' base digit)
Now with that we can write the following function:
increment :: [Base] -> [Digit] -> [Digit]
increment bases digits = evalState (sequence steps) True
where steps :: [State Carry Digit]
steps = zipWith singleDigit bases digits
What we're doing here is:
Using zipWith to "sew" the bases and digits list together on corresponding elements. The elements of this list correspond to the individual steps of the computation.
Using sequence :: [State Carry Digit] -> State Carry [Digit] to chain all the individual steps into one big step that passes the intermediate Carry state around.
Feeding True as the initial Carry input to that big chain of steps (which causes the chain to increment).
Example invocation:
>>> take 20 (iterate (increment [3,4,5,10]) [0,0,0,0])
[[0,0,0,0],[1,0,0,0],[2,0,0,0]
,[0,1,0,0],[1,1,0,0],[2,1,0,0]
,[0,2,0,0],[1,2,0,0],[2,2,0,0]
,[0,3,0,0],[1,3,0,0],[2,3,0,0]
,[0,0,1,0],[1,0,1,0],[2,0,1,0]
,[0,1,1,0],[1,1,1,0],[2,1,1,0]
,[0,2,1,0],[1,2,1,0]
]
The lessons I'd stress:
Break problems into smaller pieces. Don't try solve too much in one function! In this case, the trick was to split off the solution for single digits into its own function.
It pays very much to think carefully about the data flow in a problem: what information is needed at each step of the problem? In this case, the diagram helped reason that out, which led to the singleDigit' function.
One of the big ideas of functional programming is to separate the "shape" of the computation from its "content". In this case, the "content" is the singleDigit operation, and the "shape" of the computation—how to combine the individual steps into a big solution—is provided by the State monad and the sequence operation.
I did not write a single recursive function; instead, I made ample use of library functions like zipWith, sequence, take and iterate. You ask for a more idiomatic Haskell solution, so well, here goes: complicated recursive functions definitions are not as idiomatic as using library functions that encapsulate common recursive patterns.
This hopefully will encourage you to study monads some more. There are many, many problems out there where, if you express them in terms of one of the standard monads like State, you can reuse generic functions like sequence to solve them very easily. It's a tall learning curve but the results are worth it!
The function I'm trying to write should remove the element at the given index from the given list of any type.
Here is what I have already done:
delAtIdx :: [x] -> Int -> [x]
delAtIdx x y = let g = take y x
in let h = reverse x
in let b = take (((length x) - y) - 1) h
in let j = g ++ (reverse b)
in j
Is this correct? Could anyone suggest another approach?
It's much simpler to define it in terms of splitAt, which splits a list before a given index. Then, you just need to remove the first element from the second part and glue them back together.
reverse and concatenation are things to avoid if you can in haskell. It looks like it would work to me, but I am not entirely sure about that.
However, to answer the "real" question: Yes there is another (easier) way. Basically, you should look in the same direction as you always do when working in haskell: recursion. See if you can make a recursive version of this function.
Super easy(I think):
removeIndex [] 0 = error "Cannot remove from empty array"
removeIndex xs n = fst notGlued ++ snd notGlued
where notGlued = (take (n-1) xs, drop n xs)
I'm a total Haskell noob, so if this is wrong, please explain why.
I figured this out by reading the definition of splitAt. According to Hoogle, "It is equivalent to (take n xs, drop n xs)". This made me think that if we just didn't take one extra number, then it would be basically removed if we rejoined it.
Here is the article I referenced Hoogle link
Here's a test of it running:
*Main> removeIndex [0..10] 4
[0,1,2,4,5,6,7,8,9,10]
deleteAt :: Int -> [a] -> [a]
deleteAt 0 (x:xs) = xs
deleteAt n (x:xs) | n >= 0 = x : (deleteAt (n-1) xs)
deleteAt _ _ = error "index out of range"
Here is my solution:
removeAt xs n | null xs = []
removeAt (x:xs) n | n == 0 = removeAt xs (n-1)
| otherwise = x : removeAt xs (n-1)
remove_temp num l i | elem num (take i l) == True = i
| otherwise = remove_temp num l (i+1)
remove num l = (take (index-1) l) ++ (drop index l)
where index = remove_temp num l 1
Call 'remove' function with a number and a list as parameters. And you'll get a list without that number as output.
In the above code, remove_temp function returns the index at which the number is present in the list. Then remove function takes out the list before the number and after the number using inbuilt 'take' and 'drop' function of the prelude. And finally, concatenation of these two lists is done which gives a list without the input number.
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?