Similar functions applied to nested list in Haskell - list

Here is the problem I encountered.
I have some functions that are similar in their bodies (with a slightly difference), but they have signatures.
flatB :: [[String]] -> [[String]]
flatB [] = []
flatB [x] = [x]
flatB (a : b : xs) | isDigit (head n) = replicate (read n :: Int) a ++ flatB xs
| otherwise = a : flatB (b : xs)
where n = head b
flatC :: [String] -> [String]
flatC [] = []
flatC [x] = [x]
flatC (a : b : xs) | isDigit (head b) = replicate (read b :: Int) a ++ flatC xs
| otherwise = a : flatC (b : xs)
I'm expecting the function to do the following:
> flatC ["a","2","b"]
["a","a","b"]
> flatB [["a","b"],["2"]]
[["a","b"],["a","b"]]
The code above works. But I'm wondering whether there is a simpler way to achieve this?
I think that creating a typeclass may be the way, but I don't know how to do it.

The only difference is how you read the Int out of every other element on the list, which you can factor out as a function parameter:
import Text.Read (readMaybe)
flat :: (a -> Maybe Int) -> [a] -> [a]
flat _ [] = []
flat _ [x] = [x]
flat readElem (a : b : xs)
| Just n <- readElem b = replicate n a ++ flat readElem xs
| otherwise = a : flat readElem (b : xs)
flatB :: [[String]] -> [[String]]
flatB = flat readHead
where
readHead [] = Nothing
readHead (n : _) = readMaybe n
flatC :: [String] -> [String]
flatC = flat readMaybe

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.

zipWith Function Implemented Using Map and Zip Functions

I am attempting to implement the zipWith function via the zip and map functions, but I am getting an error that reads: "error: parse error on input '::' My code is below and and I am unsure of what I have done wrong
zipWith` :: (a -> b -> c) -> [a] -> [b] -> [c]
zipWith` f x y = zip x $ map f y
You have to use ' symbol and not ` ; then, to combine the function you need to use uncurry:
zipWith' :: (a -> b -> c) -> [a] -> [b] -> [c]
zipWith' f xs ys = map (uncurry f) (zip xs ys)
why is that, well the type of zip is:
zip :: [a] -> [b] -> [(a, b)]
but the function f is f :: (a -> b -> c), so, with the help of uncurry,
uncurry :: (a -> b -> c) -> (a, b) -> c
you can map the function f into the [(a, b)], transforming it into [c].
As Damian points out, zipWith` doesn't work with the trailing backtick -- the backtick has a special meaning in Haskell. Rename it to zipWith'.
zipWith' :: (a -> b -> c) -> [a] -> [b] -> [c]
Then of course you have to actually write the solution. With explicit recursion you've got
zipWith' _ _ [] = []
zipWith' _ [] _ = []
zipWith' f (x:xs) (y:ys) = f x y : zipWith' f xs ys
but using map and zip you could apply it like this:
zipWith' f xs ys = map (\(x,y) -> f x y) . zip xs $ ys
or more easily-read:
zipWith' f xs ys = map (\(x,y) -> f x y) zipped
where zipped = zip xs ys

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"]

Implement insert in haskell with foldr

How to implement insert using foldr in haskell.
I tried:
insert'' :: Ord a => a -> [a] -> [a]
insert'' e xs = foldr (\x -> \y -> if x<y then x:y else y:x) [e] xs
No dice.
I have to insert element e in list so that it goes before first element that is larger or equal to it.
Example:
insert'' 2.5 [1,2,3] => [1.0,2.0,2.5,3.0]
insert'' 2.5 [3,2,1] => [2.5,3.0,2.0,1.0]
insert'' 2 [1,2,1] => [1,2,2,1]
In last example first 2 is inserted one.
EDIT:
Thanks #Lee.
I have this now:
insert'' :: Ord a => a -> [a] -> [a]
insert'' e xs = insert2 e (reverse xs)
insert2 e = reverse . snd . foldr (\i (done, l) -> if (done == False) && (vj e i) then (True, e:i:l) else (done, i:l)) (False, [])
where vj e i = e<=i
But for this is not working:
insert'' 2 [1,3,2,3,3] => [1,3,2,2,3,3]
insert'' 2 [1,3,3,4] => [1,3,2,3,4]
insert'' 2 [4,3,2,1] => [4,2,3,2,1]
SOLUTION:
insert'' :: Ord a => a -> [a] -> [a]
insert'' x xs = foldr pom poc xs False
where
pom y f je
| je || x > y = y : f je
| otherwise = x : y : f True
poc True = []
poc _ = [x]
Thanks #Pedro Rodrigues (It just nedded to change x>=y to x>y.)
(How to mark this as answered?)
You need paramorphism for that:
para :: (a -> [a] -> r -> r) -> r -> [a] -> r
foldr :: (a -> r -> r) -> r -> [a] -> r
para c n (x : xs) = c x xs (para c n xs)
foldr c n (x : xs) = c x (foldr c n xs)
para _ n [] = n
foldr _ n [] = n
with it,
insert v xs = para (\x xs r -> if v <= x then (v:x:xs) else (x:r)) [v] xs
We can imitate paramorphisms with foldr over init . tails, as can be seen here: Need to partition a list into lists based on breaks in ascending order of elements (Haskell).
Thus the solution is
import Data.List (tails)
insert v xs = foldr g [v] (init $ tails xs)
where
g xs#(x:_) r | v <= x = v : xs
| otherwise = x : r
Another way to encode paramorphisms is by a chain of functions, as seen in the answer by Pedro Rodrigues, to arrange for the left-to-right information flow while passing a second copy of the input list itself as an argument (replicating the effect of tails):
insert v xs = foldr g (\ _ -> [v]) xs xs
where
g x r xs | v > x = x : r (tail xs) -- xs =#= (x:_)
| otherwise = v : xs
-- visual aid to how this works, for a list [a,b,c,d]:
-- g a (g b (g c (g d (\ _ -> [v])))) [a,b,c,d]
Unlike the version in his answer, this does not copy the rest of the list structure after the insertion point (which is possible because of paramorphism's "eating the cake and having it too").
Here's my take at it:
insert :: Ord a => a -> [a] -> [a]
insert x xs = foldr aux initial xs False
where
aux y f done
| done || x > y = y : f done
| otherwise = x : y : f True
initial True = []
initial _ = [x]
However IMHO using foldr is not the best fit for this problem, and for me the following solution is easier to understand:
insert :: Int -> [Int] -> [Int]
insert x [] = [x]
insert x z#(y : ys)
| x <= y = x : z
| otherwise = y : insert x ys
I suppose fold isn't handy here. It always processes all elements of list, but you need to stop then first occurence was found.
Of course it is possible, but you probable don't want to use this:
insert' l a = snd $ foldl (\(done, l') b -> if done then (True, l'++[b]) else if a<b then (False, l'++[b]) else (True, l'++[a,b])) (False, []) l