Tuples Pattern Matching list Haskell - list

I am trying to implement a function where I have a list of 2-tuples and it returns the tuples that correspond to True. The first character is a String and the second character is a Boolean. This is what I want:
pack [ ("a", True), ("b", False), ("c", False), ("d", True) ]
returns [ ("a", True), ("d", True) ]
Here is my code:
pack :: [String] -> [Bool] -> [(String, Bool)]
pack [] [] = []
pack (x:xs) [] = []
pack [] (y:ys) = []
pack (x:xs) (True:ys) = (x, True) : pack xs ys
pack (x:xs) (False:ys) = pack xs ys
I can only get { returns [("a", True), ("d", True)] } only by typing in
pack ["a", "b", "c", "d"] [True, False, False, True]
and this is not what I want and am confused how to approach this. Any help, guidance, or link would be much appreciated.

I'm going to use the description of what you are trying to implement to show you what my steps towards a solution would be. Hopefully that helps you converge on your own solutions in the future.
If I rephrase it, you want a function with the following signature:
pack :: [(String, Bool)] -> [(String, Bool)]
That is, you have a list of 2-tuples (the first element being a String, the second element being a Bool) and you want to end up with a list of the same type.
You want to filter all the tuples of this list and only keep the ones with a True value. The prelude happens to have a function just for that:
filter :: (a -> Bool) -> [a] -> [a]
The first argument of filter, a function a -> Bool called a predicate, lets you define what you want to keep in the second argument (the first [a]).
Note that a can be any type at all, so we could replace a with (String, Bool) and filter would have the following type:
filter :: ((String, Bool) -> Bool) -> [(String, Bool)] -> [(String, Bool)]
It's starting to look closer and closer to our target signature for pack! What we are missing is the predicate (String, Bool) -> Bool that will tell filter what we want to keep:
isTrue :: (String, Bool) -> Bool
isTrue (_, True) = True
isTrue (_, False) = False
Finally, we can implement pack in term of filter and isTrue:
pack :: [(String, Bool)] -> [(String, Bool)]
pack = filter onlyTrue
You've mentioned in a comment that you do not want to use any "built-in" function. Let's get rid of filter then, and write pack closer to the original style you've posted:
pack [] = []
pack (x:xs)
| isTrue x = x : pack xs
| otherwise = pack xs

Related

Haskell list to unitary sublist

I'm having problems turning a list to a unitary sublist
sublists :: [a] -> [[a]]
sublists [] = [[]]
sublists (x:xs) = [x:ys | ys <- sub] ++ sub
where sub = sublists xs
I need a function that given
sublists [True,False]
returns
[[True],[False]] instead of [[True,False],[True],[False],[]]
But I just donĀ“t know how and feel like punching my computer in the face.
I hope I am clear. Thanks!
So you want a function that converts a to [a]. Okay...
makeList = \x -> [x]
(why did I write it as a lambda? keep reading)
So you want a function that converts a to [a] within a list. Okay...
makeListsInList = map (\x -> [x])
done.
You can use the function pure :: Applicative f => a -> f a to wrap values into a list, since the instance of Applicative for [] wraps elements in a singleton list.
So you can define your function as:
sublists :: [a] -> [[a]]
sublists = map pure
For example:
Prelude> sublists [True, False, False, True]
[[True],[False],[False],[True]]

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 compare elements in a [[]]?

I am dealing with small program with Haskell. Probably the answer is really simple but I try and get no result.
So one of the part in my program is the list:
first = [(3,3),(4,6),(7,7),(5,43),(9,9),(32,1),(43,43) ..]
and according to that list I want to make new one with element that are equal in the () =:
result = [3,7,9,43, ..]
Even though you appear to have not made the most minimal amount of effort to solve this question by yourself, I will give you the answer because it is so trivial and because Haskell is a great language.
Create a function with this signature:
findIdentical :: [(Int, Int)] -> [Int]
It takes a list of tuples and returns a list of ints.
Implement it like this:
findIdentical [] = []
findIdentical ((a,b) : xs)
| a == b = a : (findIdentical xs)
| otherwise = findIdentical xs
As you can see, findIdentical is a recursive function that compares a tuple for equality between both items, and then adds it to the result list if there is found equality.
You can do this for instance with list comprehension. We iterate over every tuple f,s) in first, so we write (f,s) <- first in the right side of the list comprehension, and need to filter on the fact that f and s are equal, so f == s. In that case we add f (or s) to the result. So:
result = [ f | (f,s) <- first, f == s ]
We can turn this into a function that takes as input a list of 2-tuples [(a,a)], and compares these two elements, and returns a list [a]:
f :: Eq a => [(a,a)] -> [a]
f dat = [f | (f,s) <- dat, f == s ]
An easy way to do this is to use the Prelude's filter function, which has the type definition:
filter :: (a -> Bool) -> [a] -> [a]
All you need to do is supply predicate on how to filter the elements in the list, and the list to filter. You can accomplish this easily below:
filterList :: (Eq a) => [(a, a)] -> [a]
filterList xs = [x | (x, y) <- filter (\(a, b) -> a == b) xs]
Which behaves as expected:
*Main> filterList [(3,3),(4,6),(7,7),(5,43),(9,9),(32,1),(43,43)]
[3,7,9,43]

removing tuples from list (Haskell)

I want to write a function that takes as argument a list of tuples like this:
remove' [ ("a", True), ("b", False), ("c", False), ("d", True) ]
I would like to return a list of tuples that have False as their second value, so I'd like my function to return
[ ("b", False), ("c", False) ]
Here's what I have so far but it won't load in GHCi. can anyone help me out? Thanks
remove' :: [(a,b)] -> [(a,b)]
remove' [(a,b)] = [ c | c <- [(a,b)], c `notElem` True ]
Since you want to match the second element of the tuples, you need to pick the second element from the tuple and compare it with False like this
remove' :: [(a, Bool)] -> [(a, Bool)]
remove' xs = [c | c <- xs, snd c == False]
The snd function will get second element from each of the tuples and compare them with False. Only if they match, they will be gathered in the resulting list.
Since the second elements are booleans, you can make use of the not function like this
[c | c <- xs, (not . snd) c]
We can express the same wihtout the dot notation like this
[c | c <- xs, not(snd(c))]
Note: In your program, you have
remove' [(a,b)] = ...
it means that, it will be executed only when remove is called with a list of tuples of size 1. You can check that like this
remove' :: [(a, Bool)] -> [(a, Bool)]
remove' [(a, b)] = [(a, b)]
remove' [ ("a", True), ("b", False), ("c", False), ("d", True) ]
will print
Non-exhaustive patterns in function remove'
It means the patterns you specified in the function definition is not covering all the possible inputs. Since we need process a list of tuples of any length, we accept it in xs and use it in the List Comprehension.
I'm surprised no one has yet said
remove' = filter (not . snd)
You just need filter and select second item in lambda:
filter (\x -> (snd x) == False) [("a", False), ("b", True)]
Response:
[("a",False)]

List of Tuples as a function Parameter in Haskell

How do define a function with a parameter that is a list of tuples? So an example of the input would be
[("hey", False), ("you", True)]
My function takes the list of tuples as: [(String, Bool)]
So here is what it looks like:
aFunc :: [(String, Bool)] -> Bool
aFunc ???? =
So what do I fill in for the ???? to be able to access my tuple? Any help would be great. Thanks.
Edit:
aFunc :: [(String, Bool)] -> Bool
aFunc aTuple = mapM_ lookup aTuple?
So how do I access my tuple in a function? That doesn't work.
It looks like you're trying to implement your own version of lookup. You can write a simple version using list comprehension:
lookup' :: String -> [(String,Bool)] -> Bool
lookup' k lkp = head $ [v | (k',v) <- lkp, k'==k]
Or using filter:
lookup'' :: String -> [(String,Bool)] -> Bool
lookup'' k lkp = snd $ head $ filter ((==k) . fst) lkp
Notice that these versions are unsafe - that is, they'll fail with an ugly and uninformative error if the list doesn't contain your item:
ghci> lookup' "foo" [("bar",True)]
*** Exception: Prelude.head: empty list
You can solve this issue by writing your own custom error message:
lookupErr :: String -> [(String,Bool)] -> Bool
lookupErr k lkp = case [v | (k',v) <- lkp, k'==k] of
(v:_) -> v
[] -> error "Key not found!"
A better approach is to return a Maybe Bool instead:
lookupMaybe :: String -> [(String,Bool)] -> Maybe Bool
lookupMaybe k lkp = case [v | (k',v) <- lkp, k'==k] of
(v:_) -> Just v
[] -> Nothing
The library version takes this approach, and has a more generic signature:
lookup :: (Eq a) => a -> [(a,b)] -> Maybe b
You can read its implementation here.