Haskell - My own zip3 function - list

Is there a better way to re-create this function? It compiles fine.
This is what I have:
zip3' :: [a] -> [b] -> [c] -> [(a,b,c)]
zip3' [] _ _ = []
zip3' _ [] _ = []
zip3' _ _ [] = []
zip3' (a:as) (b:bs) (c:cs) = (a,b,c) : zip3' as bs cs
I'm just wondering if there is a better way to summarize this:
zip3' [] _ _ = []
zip3' _ [] _ = []
zip3' _ _ [] = []

It works fine. If you want to make the program shorter, you can write:
zip3' :: [a] -> [b] -> [c] -> [(a,b,c)]
zip3' (a:as) (b:bs) (c:cs) = (a,b,c) : zip3' as bs cs
zip3' _ _ _ = []
Since the first line will only fail to fire if there is at least one of the three lists that is not (_:_) (so []). But this is sometimes seen as an anti-pattern, since in a very unlike event that one adds a constructor to the list data type, this might end up with an empty list (whereas in that case, we perhaps better get an error). I agree that for lists this is close to impossible: a lot of libraries and programs would no longer work. But in general it is not uncommon that you for instance design a data type, and later change your mind and add an extra constructor.
If we inspect the source code of zip3 :: [a] -> [b] -> [c] -> [(a,b,c)], then we see it is implemented that way [source]:
zip3 :: [a] -> [b] -> [c] -> [(a,b,c)]
-- Specification
-- zip3 = zipWith3 (,,)
zip3 (a:as) (b:bs) (c:cs) = (a,b,c) : zip3 as bs cs
zip3 _ _ _ = []
For some reason zip itself is implemented in the "question" style [source]:
zip :: [a] -> [b] -> [(a,b)]
zip [] _bs = []
zip _as [] = []
zip (a:as) (b:bs) = (a,b) : zip as bs

There's nothing inherently wrong with your approach, but you can collapse the first three cases into a catch-all at the end.
zip3' :: [a] -> [b] -> [c] -> [(a,b,c)]
zip3' (a:as) (b:bs) (c:cs) = (a,b,c) : zip3' as bs cs
zip3' _ _ _ = []
In fact, this is how GHC does it.

Related

How can I only slice the list when the function is not true in haskell?

I would like to slice my list when the function is not true, but I do not have an idea what I have to give back in the otherwise case. Do you have any idea ?
Example :
sliceBy odd [1..5] == [[1],[2],[3],[4],[5]]
sliceBy odd [1,3,2,4,5,7,4,6] == [[1,3],[2,4],[5,7],[4,6]]
sliceBy even [1,3,2,4,5,7,4,6] == [[],[1,3],[2,4],[5,7],[4,6]]
sliceBy :: (a -> Bool) -> [a] -> [[a]]
sliceBy _ [] = []
sliceBy _ [x] = [[x]]
sliceBy f (x:xs)
| f x = [x] : sliceBy f xs
| otherwise = ??
You can make use of span :: (a -> Bool) -> [a] -> ([a], [a]) and break :: (a -> Bool) -> [a] -> ([a], [a]) to get the longest prefixes where the list does/does not satisfy a given predicate. You thus can use this to make two functions sliceBy and sliceByNot that call each other:
sliceBy :: (a -> Bool) -> [a] -> [[a]]
sliceBy _ [] = []
sliceBy f xs = … : …
where (xp, xnp) = span f xs
sliceByNot :: (a -> Bool) -> [a] -> [[a]]
sliceByNot _ [] = []
sliceByNot f xs = … : …
where (xnp, xp) = break f xs
Where you need to fill in the … parts. The two functions thus should call each other.

Splitting list into odd and even (Haskell)

I need to create a function that will take a list of integers and split them into 2 lists, one with odd numbered and the other even
split :: [a] -> ([a], [a])
split = undefined
Above is the function baseline, below is current attempt I have
split :: [a] -> ([a], [a])
split [] = ([],[])
split (x:xs) | x mod 2 == 0 = ([],[x:split xs])
| x mod 2 /= 0 = ([x:split xs],[])
| otherwise = ([],[])
explicit recursion:
split :: Integral a => [a] -> ([a], [a])
split [] = ([], [])
split (x:xs)
| even x = (x:ys, zs)
| otherwise = (ys, x:zs)
where
(ys, zs) = split xs
implicit recursion:
splitf :: Integral a => [a] -> ([a], [a])
splitf xs = foldr (\x (ys, zs) -> if even x then (x:ys, zs) else (ys, x:zs))
([], []) xs
which you can eta reduce to point-free style:
splitf2 :: Integral a => [a] -> ([a], [a])
splitf2 = foldr (\x (ys, zs) -> if even x then (x:ys, zs) else (ys, x:zs))
([], [])
I think the code is self explanatory. If there is anything I need to further explain, please let me know.

infinite type error reversing a list in Haskell

I'm trying to implement the reverse of a list:
myLast :: [a] -> a
myLast [] = error "No end for empty lists!"
myLast [x] = x
myLast (_:xs) = myLast xs
myReverse :: [a] -> [a]
myReverse (x:xs) = myLast xs + myReverse xs
but I get this error:
/workspaces/hask_exercises/exercises/src/Lib.hs:42:32: error:
* Occurs check: cannot construct the infinite type: a ~ [a]
* In the second argument of `(+)', namely `myReverse xs'
In the expression: myLast xs + myReverse xs
In an equation for `myReverse':
myReverse (x : xs) = myLast xs + myReverse xs
* Relevant bindings include
xs :: [a] (bound at src/Lib.hs:42:14)
x :: a (bound at src/Lib.hs:42:12)
myReverse :: [a] -> [a] (bound at src/Lib.hs:41:1)
|
42 | myReverse (x:xs) = myLast xs + myReverse xs
| ^^^^^^^^^^^^
What does it mean that cannot construct the infinite type: a ~ [a]? I get this error a lot and would like to understand what it means.
The (+) :: Num a => a -> a -> a function adds two numbers (of the same type) together. So for example if a ~ Int, it will add two Ints together, but not an Int and a [Int].
But even if the (+) operator for example would prepend an item to a list, it would still not reverse the list correctly: your function has no base case what to do for an empty list, and your recursive list does nothing with the first item x of the list (x:xs).
A simple way to reverse:
myReverse :: [a] -> [a]
myReverse [] = []
myReverse (x:xs) = myReverse xs ++ [x]
But that is not efficient: appending two items will take linear time in the size of the left list. You can work with an accumulator: a parameter that you each time update when you make a recursive call. This looks like:
myReverse :: [a] -> [a]
myReverse [] = go []
where go ys (x:xs) = …
where go ys [] = …
where filling in the … parts are left as an exercise.
You have
myLast :: [a] -> a
myReverse :: [a] -> [a]
myReverse (x:xs) = myLast xs + myReverse xs
\___a___/ \____[a]___/
(x:xs) :: [a]
---------------
x :: a
xs :: [a] xs :: [a]
myLast :: [a] -> a myReverse :: [a] -> [a]
------------------------- ----------------------------
myLast xs :: a myReverse xs :: [a]
myReverse (x:xs) :: [a]
but
> :t (+)
(+) :: Num a => a -> a -> a
which means that the type of the thing on the left of + and the type of the thing on the right must be the same.
But they can't be: as we just saw above, in your code the first (of myLast xs) is some type a, and the second (of myReverse xs) is [a] the list of those same as.
These two can't be the same, because it would mean
a ~ [a] OK, this is given to us, then
a ~ [a] we can use it, so that
--------------
a ~ [[a]] this must hold;
a ~ [a] we know this, then
--------------
a ~ [[[a]]] this must also hold; and
a ~ [a] ........
-------------- ........
a ~ [[[[a]]]] ........
.........................
and so on ad infinitum, thus making this a an "infinite" type. Hence the error.
You could fix it by replacing the + with
(+++) :: a -> [a] -> [a]
and implementing it to do what you need it to do.
You will also need to fix your off-by-one error whereby you completely ignore the first element in the received input, x.

own nub function - how to use foldl/foldr?

Here is my own implementation of nub (remove duplicates):
nub :: (Eq a) => [a] -> [a]
nub lista = nub_rec lista []
where
nub_rec :: (Eq a) => [a] -> [a] -> [a]
nub_rec [] acc = acc
nub_rec (x:xs) acc = nub_rec (filter (\y -> if y == x then False else True) xs) (x:acc)
I consider how to use foldr/foldl to implement nub, could you help me ? I can't see a way.
First, your implementation of nub is bit more complex than it needs to be (and it reverses the order of elements in the list). Here's a simpler one:
myNub :: Eq a => [a] -> [a]
myNub (x:xs) = x : filter (/= x) (myNub xs)
myNub [] = []
Now, if we want to use foldr to write a function that will output, not just an "aggregate" but a full list, it's useful to first have a look at the simplest foldr-based function that takes in a list and spits out a list:
myNoop :: [a] -> [a]
myNoop l = foldr (\ x xs -> x : xs) [] l
Given that, the filter must be inserted somewhere. Since I assume this is a homework, I'll leave that to the OP as an exercise :)
Solution only with filter and foldr without direct (or self) recursion:
removeDuplicates :: Eq a => [a] -> [a]
removeDuplicates = foldr (\z ys -> z : filter (/= z) ys) []

How to insert a list in a list in all possible ways?

I am trying to enumerate all the possible merges of two lists.
In example inserting "bb" into "aaa" would look like
["bbaaa", "babaa", "baaba", "baaab", "abbaa", "ababa", "abaab", "aabba", "aabab", "aaabb"]
What I currently did is this
import Data.List
insert'' :: Char -> String -> [(String, String)] -> String
insert'' _ _ ([]) = []
insert'' h b ((x, y):xs) =
(x ++ [h] ++ (insert' (b, y))) ++ (insert'' h b xs)
insert' :: (String, String) -> String
insert' ([], ys) = ys
insert' (xs, ys) =
insert'' h b lists
where
h = head xs
b = tail xs
lists = zip (tails ys) (inits ys)
This returns for ("aaa", "bb")
"bbaaababaaabaababbaababaababbabababb"
a concatenated string, I tried making it a list of strings, but I just cannot wrap my head around this function. I always seems to get infinite type construction.
How could I rewrite the function, so it would return a list of strings?
An other implementation idea as in Daniel Wagners first post is to choose in each step a element from one of the lists and prepending it to the results generated by the function called with only the remaining parts of the list:
interleave :: [a] -> [a] -> [[a]]
interleave xs [] = [xs]
interleave [] ys = [ys]
interleave xs#(x : xs') ys#(y : ys') =
map (x :) (interleave xs' ys) ++ map (y :) (interleave xs ys')
For your intial example this produces:
ghci> interleave "bb" "aaa"
["bbaaa","babaa","baaba","baaab","abbaa","ababa","abaab","aabba","aabab","aaabb"]
Here is one implementation idea: for each element in the first list, we will choose (nondeterministically) a position in the second list to insert it, then recurse. For this to work, we first need a way to nondeterministically choose a position; thus:
choose :: [a] -> [([a], [a])]
choose = go [] where
go before xs = (before, xs) : case xs of
[] -> []
x:xs -> go (x:before) xs
For example:
> choose "abcd"
[("","abcd"),("a","bcd"),("ba","cd"),("cba","d"),("dcba","")]
Now we can use this tool to do the insertion:
insert :: [a] -> [a] -> [[a]]
insert [] ys = [ys]
insert (x:xs) ys = do
(before, after) <- choose ys
rest <- insert xs (reverse after)
return (before ++ [x] ++ rest)
In ghci:
> insert "ab" "cde"
["abcde","aebcd","adebc","acdeb","cabde","caebd","cadeb","dcabe","dcaeb","edcab"]
In this answer, I will give the minimal change needed to fix the code you already have (without completely rewriting your code). The first change needed is to update your type signatures to return lists of strings:
insert'' :: Char -> String -> [(String, String)] -> [String]
insert' :: (String, String) -> [String]
Now your compiler will complain that the first clause of insert' is returning a String instead of a [String], which is easily fixed:
insert' ([], ys) = [ys]
...and that the second clause of insert'' is trying to append a String to a [String] when running [h] ++ insert' (b, y). This one takes some thinking to figure out what you really meant; but my conclusion is that instead of x ++ [h] ++ insert' (b, y), you really want to run \t -> x ++ [h] ++ t for each element in insert' (b, y). Thus:
insert'' h b ((x, y):xs) =
(map (\t -> x ++ [h] ++ t) (insert' (b, y))) ++ (insert'' h b xs)
The complete final code is:
import Data.List
insert'' :: Char -> String -> [(String, String)] -> [String]
insert'' _ _ ([]) = []
insert'' h b ((x, y):xs) =
(map (\t -> x ++ [h] ++ t) (insert' (b, y))) ++ (insert'' h b xs)
insert' :: (String, String) -> [String]
insert' ([], ys) = [ys]
insert' (xs, ys) =
insert'' h b lists
where
h = head xs
b = tail xs
lists = zip (tails ys) (inits ys)
Now ghci will happily produce good answers:
> insert' ("aaa", "bb")
["bbaaa","babaa","baaba","baaab","abbaa","ababa","abaab","aabba","aabab","aaabb"]