Tuple function in Haskell - list

I have the function
getCode :: [(a, Int)] -> [a]
getCode = concatMap (uncurry replicate)`
I expect
getCode [(‘a’,4),(‘b’,1),(‘a’,3),(‘b’,1)]
to output
“aaaabaaab”
Instead I get an error that it does not match with the expected data type [(a,Int)], and the actual data type is [(Int,a)]. How do i change it to make it work? Or any other way?

You can swap the parameters of replicate with the flip function:
flip :: (a -> b -> c) -> b -> a -> c
flip f takes its (first) two arguments in the reverse order of f.
getCode :: [(a, Int)] -> [a]
getCode = concatMap (uncurry (flip replicate))
Or use swap from Data.Tuple to do the same thing with a tuple instead of function parameters:
getCode :: [(a, Int)] -> [a]
getCode = concatMap (uncurry replicate . swap)

Related

Haskell Function which combines Lists

I want to write a recursive function that gets two lists + a conditional as input, and outputs all possible tuples with one element each from the 1st and 2nd lists that satisfy the condition.
It should look something like this:
Combine [1,2,3] [5,6,7] (\a b -> a+b > 7) -> [(1,7),(2,6),(2,7),(3,5),(3,6),(3,7)]
I got this atm:
Combine:: [a] -> [b] -> [(a, b)]
Combine [] ys = []
Combine xs [] = []
Combine (x:xs) (y:ys) = (x,y) : Combine xs ys
However, it does not yet create all possible combinations and does not filter by condition. I really don't know how to figure this out.
Thanks in advance
You don't need a recursive function, but you need a higher order function.
combinationsFilter :: (a -> b -> Bool) -> [a] -> [b] -> [(a,b)]
combinationsFilter f as bs = filter (uncurry f) [(a, b) | a <- as, b <- bs]
[(a, b) | a <- as, b <- bs] generates all combinations of a and b.
filter... just filters the list by condition.
uncurry needed if you want pass a function with type (a -> b -> c), but not ((a, b) -> c). It converts one to the other.

Sum corresponding elements of two lists, with the extra elements of the longer list added at the end

I'm trying to add two lists together and keep the extra elements that are unused and add those into the new list e.g.
addLists [1,2,3] [1,3,5,7,9] = [2,5,8,7,9]
I have this so far:
addLists :: Num a => [a] -> [a] -> [a]
addLists xs ys = zipWith (+) xs ys
but unsure of how to get the extra elements into the new list.
and the next step is changing this to a higher order function that takes the combining function
as an argument:
longZip :: (a -> a -> a) -> [a] -> [a] -> [a]
zipWith :: (a -> b -> c) -> [a] -> [b] -> [c] is implemented as [src]:
zipWith :: (a->b->c) -> [a]->[b]->[c]
zipWith f = go
where
go [] _ = []
go _ [] = []
go (x:xs) (y:ys) = f x y : go xs ys
It thus uses explicit recursion where go will check if the two lists are non-empty and in that case yield f x y, otherwise it stops and returns an empty list [].
You can implement a variant of zipWith which will continue, even if one of the lists is empty. THis will look like:
zipLongest :: (a -> a -> a) -> [a] -> [a] -> [a]
zipLongest f = go
where go [] ys = …
go xs [] = …
go (x:xs) (y:ys) = f x y : go xs ys
where you still need to fill in ….
You can do it with higher order functions as simple as
import Data.List (transpose)
addLists :: Num a => [a] -> [a] -> [a]
addLists xs ys = map sum . transpose $ [xs, ys]
because the length of transpose[xs, ys, ...] is the length of the longest list in its argument list, and sum :: (Foldable t, Num a) => t a -> a is already defined to sum the elements of a list (since lists are Foldable).
transpose is used here as a kind of a zip (but cutting on the longest instead of the shortest list), with [] being a default element for the lists addition ++, like 0 is a default element for the numbers addition +:
cutLongest [xs, ys] $
zipWith (++) (map pure xs ++ repeat []) (map pure ys ++ repeat [])
See also:
Zip with default value instead of dropping values?
You're looking for the semialign package. It gives you an operation like zipping, but that keeps going until both lists run out. It also generalizes to types other than lists, such as rose trees. In your case, you'd use it like this:
import Data.Semialign
import Data.These
addLists :: (Semialign f, Num a) => f a -> f a -> f a
addLists = alignWith (mergeThese (+))
longZip :: Semialign f => (a -> a -> a) -> f a -> f a -> f a
longZip = alignWith . mergeThese
The new type signatures are optional. If you want, you can keep using your old ones that restrict them to lists.

Breaking up a list into sublists with recursion

I'm trying to write a function with the type declaration [(Int, Bool)] -> [[Int]]. I want the function to only add Ints to the same nested sublist if the Boolean is True. However if the Boolean is False, I want the Int associated with the next True bool to be added to a new sublist. For example: An input of
[(1,True),(2,True),(3,False),(4,True),(5,False),(6,False),(7,True)]
should return
[[1,2],[4],[7]].
My code so far:
test:: [(Int, Bool)] -> [[Int]]
test xs = case xs of
[]->[]
x:xs
| snd x == True -> [(fst x)] : test xs
| snd x == False -> test xs
I'm currently having issues on adding concurrent Ints to the same list if their bools are both True.
You can break this problem into two sub-problems.
For any given list, take the head of this list and match it against the rest of list. There are two possibilities during this matching: i) You are successful i.e. you match, and if so, you collect the matched value and continue looking for more values, or ii) You fail, i.e. you don't match, and if so, you stop immediately and return the so far matched result with rest of, not-inspected, list.
collectF :: (Eq a) => (a -> Bool) -> [a] -> ([a], [a])
collectF f [] = ([], [])
collectF f (x : xs)
| f x = let (ys, zs) = collectF f xs in (x : ys, zs)
| otherwise = ([], x : xs)
Now that you have the collectF function, you can use it recursively on input list. In each call, you would get a successful list with rest of, not-inspected, list. Apply collectF again on rest of list until it is exhausted.
groupBy :: (Eq a) => (a -> a -> Bool) -> [a] -> [[a]]
groupBy _ [] = []
groupBy f (x : xs) =
let (ys, zs) = collectF (f x) xs in
(x : ys) : groupBy f zs
*Main> groupBy (\x y -> snd x == snd y) [(1,True),(2,True),(3,False),(4,True),(5,False),(6,False),(7,True)]
[[(1,True),(2,True)],[(3,False)],[(4,True)],[(5,False),(6,False)],[(7,True)]]
I am leaving it to you to remove the True and False values from List. Also, have a look at List library of Haskell [1]. Hope, I am clear enough, but let me know if you have any other question.
[1] http://hackage.haskell.org/package/base-4.12.0.0/docs/src/Data.OldList.html#groupBy
Repeatedly, drop the Falses, grab the Trues. With view patterns:
{-# LANGUAGE ViewPatterns #-}
test :: [(a, Bool)] -> [[a]]
test (span snd . dropWhile (not . snd) -> (a,b))
| null a = []
| otherwise = map fst a : test b
Works with infinite lists as well, inasmuch as possible.
Here's how I'd write this:
import Data.List.NonEmpty (NonEmpty(..), (<|))
import qualified Data.List.NonEmpty as NE
test :: [(Int, Bool)] -> [[Int]]
test = NE.filter (not . null) . foldr go ([]:|[])
where
go :: (Int, Bool) -> NonEmpty [Int] -> NonEmpty [Int]
go (n, True) ~(h:|t) = (n:h):|t
go (n, False) l = []<|l
Or with Will Ness's suggestion:
import Data.List.NonEmpty (NonEmpty(..))
test :: [(Int, Bool)] -> [[Int]]
test = removeHeadIfEmpty . foldr prependOrStartNewList ([]:|[])
where
prependOrStartNewList :: (Int, Bool) -> NonEmpty [Int] -> NonEmpty [Int]
prependOrStartNewList (n, True) ~(h:|t) = (n:h):|t
prependOrStartNewList (n, False) l = []:|removeHeadIfEmpty l
removeHeadIfEmpty :: NonEmpty [Int] -> [[Int]]
removeHeadIfEmpty (h:|t) = if null h then t else h:t

How to remove duplicate items in nested list?

I have a Haskel function called flatten that works as such:
flatten :: [[a]] -> [a]
flatten [] = []
flatten ([]:vs) = flatten vs
flatten ((x:xs):vs) = x:flatten (xs:vs)
It takes a list of lists and combines it into one list. How can I make another function called flatten2set that works exactly like flatten (or calls flatten), but removes all duplicates, if any? I want to try and do this without tools like nub.
An example would be:
flatten2set [[1],[5,1,4],[9,1,3],[2,5]] --> [1,5,4,9,3,2]
I have attempted to implement a nub function:
nub:: Eq a => [a] -> [a]
nub (x:xs) = x : filter (/=x) (myNub xs)
nub [] = []
And when I have tried to use it like this:
flatten2set :: [[a]] -> [a]
flatten2set[x] = (myNub . flatten) [x]
I receive this error:
testing.hs:20:18: error:
• No instance for (Eq a) arising from a use of ‘myNub’
Possible fix:
add (Eq a) to the context of
the type signature for:
flatten2set :: forall a. [[a]] -> [a]
• In the first argument of ‘(.)’, namely ‘myNub’
In the expression: myNub . flatten
In the expression: (myNub . flatten) [x]
Any help would be appreciated!
You have an excellent implementation of myNub
myNub :: Eq a => [a] -> [a]
myNub (x:xs) = x : filter (/=x) (myNub xs)
myNub [] = []
Then you try to call it
flatten2set :: [[a]] -> [a]
flatten2set = myNub . flatten
But you've declared that flatten2set works for any a. The compiler is simply pointing out that that cannot be. What if we tried to call flatten2set with a list of lists of functions? It won't work because myNub requires Eq and functions are not comparable. Since we call a function that requires Eq a, we too must require Eq a.
flatten2set :: Eq a => [[a]] -> [a]
flatten2set = myNub . flatten
I took the liberty of removing the [x], which had no purpose. If you really want to have an argument, you just name the argument. There's no need to pattern match on it.
flatten2set :: Eq a => [[a]] -> [a]
flatten2set x = (myNub . flatten) x
Using [x] is an assertion that, in this case, the list will contain exactly one element, and we want flatten2set to work on lists containing any number of elements.

How do I generate all combinations of list elements to a given length with iterate?

I'm trying to write a function using iterate which should generate all combinations of the elements:
f :: [a] -> [[[a]]]
f [1,2] =
[ [[1] , [2]] -- all combinations of length 1
, [[1,1],[1,2],[2,1],[2,2]], -- all combinations of length 2
, [[1,1,1],... ] -- all combinations of length 3
, ... -- and so on
] -- infinitely
I've tried the following approach
f :: [a] -> [[[a]]]
f list = iterate genLists list
genLists :: [a] -> [[a]]
genLists list = [ [k] | k<-list ]
However, Hugs gives me the following error:
Type error in application
*** Expression : iterate genLists list
*** Term : genLists
*** Type : [a] -> [[a]]
*** Does not match : [[a]] -> [[a]]
*** Because : unification would give infinite type
I don't really know why I get the error. Also, how can I generate those combinations using only iterate? I cannot import any other module since this is an assignment.
Lets see why you get the error:
iterate :: (a -> a ) -> a -> [a]
genLists :: [a] -> [[a]]
As you can see, iterate takes a function that takes and returns the same type. However, genLists doesn't do that. It takes a list and returns a list of lists.
Since you actually want f :: [a] -> [[[a]]], genLists return type is actually fine. However, its argument type is wrong. It has to be of type genLists :: [[a]] -> [[a]]:
f :: [a] -> [[[a]]]
f xs = iterate genLists [[x] | x <- xs]
where
genLists yss = [ x : ys | x <- xs , ys <- yss]
Here is one possible implementation, using the applicative style (which you can learn more about here).
import Control.Applicative
f :: [a] -> [[[a]]]
f xs = iterate genLists $ map pure xs
where
genLists xss = (:) <$> xs <*> xss
Then,
λ> take 3 $ f [1,2]
[[[1],[2]],[[1,1],[1,2],[2,1],[2,2]],[[1,1,1],[1,1,2],[1,2,1],[1,2,2],[2,1,1],[2,1,2],[2,2,1],[2,2,2]]]
Here is an alternative, if you don't want to or cannot use applicative stuff:
f :: [a] -> [[[a]]]
f xs = iterate genLists $ map (\x -> [x]) xs
where
genLists xss = [y : ys | y <- xs, ys <- xss]