How would I define an append function that takes two lists and output 1 list.
So plusplus [1,2,3] [4,5,6]
should return [1,2,3,4,5,6]
.
I have the following so far:
plusplus :: [Int] -> [Int] -> [Int]
plusplus [] [] = []
plusplus [] [x] = [x]
plusplus [x] [] = [x]
plusplus (x:xs) (y:ys) = x: plusplus xs (y:ys)
I want to define my own ++
function, but with recursion. The code above gives an error when I actually execute it with two lists.
This is an example of an error I get with the command:
plusplus [1,2,3] [4,5,6]
[1,2,3*** Exception: baby.hs:(...): Non-exhaustive patterns in function plusplus
ok basically the only problem you have here is a missing case:
pluspluse (x:xs) [] = ...
is missing (and will cause an error)
but you can clean up quite a bit:
The first two cases are basically the same: whatever the second input is will be the result - so you can just it those a name (say ys
) and write:
plusplus [] ys = ys
(can you see how this includes your first two cases? - what is ys
in those?)
your 3rd line one will be covered by the correct last case (see below) - to see this remember that [x] == x:[]
I'll give you the complete answer in a few minutes - but you should try to figure it out:
plusplus :: [Int] -> [Int] -> [Int]
plusplus [] ys = ys
plusplus (x:xs) ? = ??
try to find the correct things to replace ?
and ??
with
you almost had it - and the answer can be:
plusplus :: [Int] -> [Int] -> [Int]
plusplus [] ys = ys
plusplus (x:xs) ys = x: plusplus xs ys
as you can see you never have to touch the second list - but need to recreate all of the first list (to link to the second)
We know that plusplus = flip (foldr (:))
. Here's the definition of foldr
:
foldr :: (a -> b -> b) -> b -> [a] -> b
foldr step = let fold acc [] = acc
fold acc (x:xs) = step x (fold acc xs)
in fold
On specializing, we get:
foldr :: (a -> b -> b) -> b -> [a] -> b
| | | | | |
| | | | | |
(:) :: (a -> [a] -> [a]) | | |
| | |
foldr (:) :: [a] -> [a] -> [a]
Here's the definition of the specialized function:
fold :: [a] -> [a] -> [a]
fold acc [] = acc
fold acc (x:xs) = x : fold acc xs
Ofcourse, we need to flip
the arguments:
plusplus :: [a] -> [a] -> [a]
plusplus [] ys = ys
plusplus (x:xs) ys = x : plusplus xs ys
That's the reason why plusplus
is defined the way it is.
Thanks guys! With the help of Carsten spotting my silly mistake.
plusplus :: [Int] -> [Int] -> [Int]
plusplus [] [] = []
plusplus (x:xs) [] = x:xs
plusplus [] (x:xs) = x:xs
plusplus (x:xs) (y:ys) = x: plusplus xs (y:ys)
This works. So for input:
plusplus [1,2,3] [4,5,6]
Output is:
[1,2,3,4,5,6]
This is really a riff on Carsten's answer, but I think it's worth going into and won't fit into a comment. One of the keys to avoiding non-exhaustive pattern errors in function definitions is to approach writing functions in a more mechanical, formulaic manner. The definition of the list type is something like this:
data [a] = [] | a : [a]
So list types have two data constructors, []
and :
. So a good first thing to try when starting your function is to write two equations, one for each of the constructors. Carsten's template (which I'm mostly copying now) is following that pattern:
plusplus :: [Int] -> [Int] -> [Int]
plusplus [] ys = _ -- Equation for empty list
plusplus (x:xs) ys = _ -- Equation for list cells
Now since we've written one pattern for each of the constructors of the type, we're now guaranteed that our patterns are exhaustive. So we stare at what we got a bit, and now we see the solution:
plusplus :: [Int] -> [Int] -> [Int]
plusplus [] ys = ys
plusplus (x:xs) ys = x : plusplus xs ys
Let's try another one! Signature:
-- | Merge two lists by alternating elements of one with the
-- other. After either list runs out, just continue with the
-- remaining elements of the other.
interleave :: [a] -> [a] -> [a]
interleave xs ys = _
Let's expand this to two equations by splitting the xs
variable according to the two constructors, and fill in the easy parts on the right hand side:
interleave :: [a] -> [a] -> [a]
interleave [] ys = ys -- this one was easy
interleave (x:xs) ys = x : _ -- we know it has to start with `x`
Now we can go two ways. The first one is we could take the second equation and split it into two cases for ys
:
interleave :: [a] -> [a] -> [a]
interleave [] ys = ys
interleave (x:xs) [] = x : _
interleave (x:xs) (y:ys) = x : _
And filling in those blanks is easy:
interleave :: [a] -> [a] -> [a]
interleave [] ys = ys
interleave (x:xs) [] = x : xs
interleave (x:xs) (y:ys) = x : y : interleave xs ys
The second way is, instead of splitting ys
on the constructors' cases, to notice that this works:
interleave :: [a] -> [a] -> [a]
interleave [] ys = ys
interleave (x:xs) ys = x : interleave ys xs
So by going about it systematically based on the constructors we know for sure that all combinations are covered.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.