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.
Related
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
Basically I have this exercise: Recall the StudentMark type synonym from last week. Write a recursive function:
listMarks :: String -> [StudentMark] -> [Int]
which gives a list of the marks for a particular student; for example:
listMarks "Joe" [("Joe", 45), ("Sam", 70), ("Joe", 52)] = [45,52]
This was the way I wrote the function:
type StudentMark = (String, Int)
listMarks :: String -> [StudentMark] -> [Int]
listMarks _ [] = []
listMarks std (x:xs)
| std == fst x = snd x : listMarks (fst x) xs
| otherwise = listMarks (fst x) xs
This does not work if a string from the list is different from the "std" string. I would like to understand why and how could I make this work? Thank you!
Easy Fix
Just change the guard | otherwise = listMarks std xs. I would also change it in the guard above, as | std == fst x = snd x : listMarks std xs as yes, they are equal, but it makes it more clear what you want to achieve. so your code would be:
type StudentMark = (String, Int)
listMarks :: String -> [StudentMark] -> [Int]
listMarks _ [] = []
listMarks std (x:xs)
| std == fst x = snd x : listMarks std xs
| otherwise = listMarks std xs
Better Versions
As you can see, you ae calling the function with always the same first argument, so it's highly likely you can write a neater version. Here are two quick ideas:
List Comprehension
Personally my favourite, list comprehensions are very versitile and clear:
listMarks' :: String -> [StudentMark] -> [Int]
listMarks' str marks = [m |(n,m) <- marks, n==str]
Basically you filter the list based on the first element, and then you return the second one.
Higher Order Functions
With higher order functions map, filter and fold, you can do as much as recursion and lcs, but often looks tidier. You want to, again, filter the list based on the first element, and then you return the second one.
listMarks'' :: String -> [StudentMark] -> [Int]
listMarks'' str = map snd . filter (\(n,_) -> n == str)
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]
I want to make a function that looks up a String in a list of type [(String, Int)] and returns the Int paired with the String.
Like this:
λ> assignmentVariable "x" [("x", 3), ("y", 4), ("z", 1)]
3
Here's what I've tried:
assignmentVariable :: String -> [(String, Int)] -> Int
assignmentVariable [] = error "list is empty"
assignmentVariable n (x:xs) = if x == n
then xs
else assignmentVariable
How could I write this?
Let's take the posted code:
assignmentVariable::String -> [(String, Integer)] -> Integer
assignmentVariable [] = error "list is empty"
assignmentVariable n (x:xs) = if x == n then xs else ...
The first equation has only one argument, while the second has two. Let's fix that.
assignmentVariable::String -> [(String, Integer)] -> Integer
assignmentVariable _ [] = error "list is empty"
assignmentVariable n (x:xs) = if x == n then xs else ...
Since we do x == n, these variables must be of the same type.
However, n::String and x::(String,Integer). We need to split x into its components before comparing.
assignmentVariable::String -> [(String, Integer)] -> Integer
assignmentVariable _ [] = error "list is empty"
assignmentVariable n ((m,x):xs) = if m == n then xs else ...
The result xs is a list, not an Integer as the type signature suggests. You just want x there.
assignmentVariable::String -> [(String, Integer)] -> Integer
assignmentVariable _ [] = error "list is empty"
assignmentVariable n ((m,x):xs) = if m == n then x else ...
Finally, the recursive call. When m/=n, we want to try the other pairs in the list xs, so:
assignmentVariable::String -> [(String, Integer)] -> Integer
assignmentVariable _ [] = error "list is empty"
assignmentVariable n ((m,x):xs) = if m == n
then x
else assignmentVariable n xs
You want to pattern-match on the pair.
assignmentVariable expected ((key, value) : rest)
If the variable name matches the expected name, the first element of the pair…
= if key == expected
You return the associated value, the second element of the pair.
then value
Otherwise, you try to find the value in the rest of the list.
else assignmentVariable expected rest
You can implement it without pattern-matching, of course:
assignmentVariable expected list
= if expected == fst (head list)
then snd (head list)
else assignmentVariable expected (tail list)
However, this is not the usual style in Haskell code.
This function also exists in the Prelude, by the name of lookup.
You're halfway there, actually!
First, it would be better to make a more general type signature, and a better name:
myLookup :: (Eq a) => a -> [(a, b)] -> b
You've done well to have sorted out the edge case of [], but you've not quite finished:
myLookup _ [] = error "myLookup: empty list."
myLookup n ((x, b):xs) = if x == n
then b
else myLookup n xs
Your problem was what you put after the else: you weren't recursively calling the function, you were returning the function, which doesn't make any sense - you need to call it again with different arguments to recur.
If you want to improve, try making a similar function of type Eq a => a -> [(a, b)] -> Maybe b for a challenge.
Just for posterity, I would like to propose an alternative implementation:
assignmentVariables :: Eq a => a -> [(a, b)] -> [b]
assignmentVariables n xs = [v | (n', v) <- xs, n == n']
You can run it in ghci:
> assignmentVariables "x" [("x", 3), ("y", 4), ("z", 1)]
[3]
"Ah!", I hear you say, "But it returns [3] and not 3!". But don't give up on it yet; there are several advantages of the behavior of this function over the behavior you proposed.
The type of assignmentVariables is more honest than the type of assignmentVariable. It doesn't promise to return a value when it doesn't find the given key in its lookup table. This means that, unlike your version, this version will not cause runtime crashes. Moreover, it has a clean way to report the unlikely situation where there are conflicts in the lookup table: it will return all values associated with the given key, even if there are many.
The consumer of the call then gets to decide how to handle the exceptional cases: one can write
case assignmentVariables key lookupTable of
[] -> -- do something appropriate to complain about missing keys
[value] -> -- do something with the value
values -> -- do conflict resolution; for example, use the first value or complain or something
or may simply treat the output of assignmentVariables as a nondeterministic value. The key here is that you are not locked into one behavior (which, of all the choices, crashing? really?).
I have a function that turns a list to a list of tuples where every key has a value of one. I want to do this by using parallelism. Should par an pseq in the parMap function or in the main_?
parMap :: [String] -> [(String, Int)]
parMap [] = []
parMap (k:xs) = do
b <- par (k, 1)
bs <- parMap xs
return (b:bs)
map_ :: [String] -> [(String, Int)]
map_ [] = []
map_ (k:xs) = (k, 1) : map_ xs
main_ = do list <- getWords "test.txt"
print $ M.toList $ reduce $ group $ map_ list
Your definition is quite close to this way of defining parMap:
parMap :: (a -> b) -> [a] -> Eval [b]
parMap f [] = return []
parMap f (a:as) = do
b <- rpar (f a)
bs <- parMap f as
return (b:bs)
To use it, call runEval on the resulting Eval monad, e.g.:
main = do list <- getWords "test.txt"
let pairs = runEval $ parMap (\x -> (x,1)) list
...
Update: It looks like rpar and rseq is just another way of utilizing par and pseq as a monad. The reason I used it is because they are well documented in the book Parallel and Concurrent Programming in Haskell and the parconc package. You may also be able to find earlier revisions of the book content for free on the Web.