Searching in List of Tuples - haskell

I have a list of tuples stored in a text file.
[(1,"123","Shiva","address #1",77000),(2,"123","Sina","address #2", 1900)]
The first element of each tuple is acount_Id and the second element of each tuple is password and in the application I tend to read the list from the file and ask for account no and password from the user and look for it in the file. I tried this:
x <- readFile "database.txt"
y <- tuples x
let account = [(a,b)|(a,b,c,d,e) <- y, ac_no ==a , pass == b]
tuples is a function that takes a string and give output of IO [(AccNo, Pass, Name, Address, Balance)] data type
Any idea how can I improve this process by using higher order function instead of list processing?
Thanks in advance!

There is a function lookup which has the type signature:
lookup :: Eq a => a -> [(a, b)] -> Maybe b
But this is only defined for pairs.
One option would be to use types to specialize to get this arrangement.
data UserDetails = UserDetails {
password :: String
address :: String
}
And define your list as (String,UserDetails) pairs, then you'd be able to use the lookup function. Putting your data into types (rather than just lots of strings) is in general a really good thing to do anyway, so I think this would be good.
If you did want to use a higher-order function, take a look at find, which will return the first of a list matching a pattern.
Something like
type UserDataAssociation = (String,String,String,String,String)
findMatchingAssociations :: [UserDataAssociation] -> String -> Maybe UserDataAssociation
findMatchingAssociations xs password = find (\(pw,a) -> pw == password) xs

Related

How do I test that something is valid for all elements in a map?

I have the following things in my application:
newtype User = User Text
newtype Counts = Counts (Map User Int)
subjectUnderTest :: Counts -> Text
An example of correct output would be
> subjectUnderTest $ fromList [(User "foo", 4), (User "bar", 4), (User "qux", 2)]
"4: foo, bar\n2: qux"
I would like to write property-based tests that verify things like "all users are represented in the output", "all counts are represented in the output" and "all users are on the same line as their corresponding count". In common for these properties is that the wording of them starts with "all ..."
How do I write a property that verifies that something is valid for each element in the Map?
I'm assuming that this question is only a simplified representation of something more complex, so here's a couple of things strategies to consider:
Split up the functionality
It looks like subjectUnderTest does two unrelated things:
It groups the values in the map by value, instead of by key.
It formats, or pretty-prints, the inverted map.
If you can split up the functionality into those two steps, they're easier to test in in isolation.
The first step, you can make parametrically polymorphic. Instead of testing a function with the type Counts -> Text, consider testing a function with the type Eq b => Map a b -> [(b, [a])]. Property-based testing is easier with parametric polymorphism, because you get certain properties for free. For example, you can be sure that the values in the output can only come from the input, because there's no way to conjure a and b values out of thin air.
You're still going to have to write tests for the properties you ask about. Write a function with a type like Eq b => Map a b -> Testable. If you want to test that all the values are there, pull them out of the map and make list of them. Sort the list and nub it. It's now a [b] value. That's your expected output.
Now call your function. It returns something like [(b, [a])]. Map it using fst, sort and nub it. That list should be equal to your expected output.
For the next step (pretty-printing), see the next section.
Roundtrips
When you want to property-base pretty-printing, the easiest approach is usually to bite the bullet and also write a parser. The printer and the parser should be the dual of each other, so if you have a function MyType -> String, your should have a parser with the type String -> Maybe MyType.
You can now write a general property like MyType -> Testable. It takes as input a value of MyType (let's call it expected). You now produce a value (let's call it actual) as actual = parse $ print expected. You can now verify that Just expected === actual.
If the particular String format is important, I'd follow it up with a few actual examples, using good old parametrised tests.
Just because you're doing property-based testing doesn't mean that a 'normal' unit test can't be useful as well.
Example
Here's a simple example of what I meant above. Assume that
invertMap :: (Ord b, Eq b) => Map a b -> [(b, [a])]
you can define one of the properties as:
allValuesAreNowKeys :: (Show a, Ord a) => Map k a -> Property
allValuesAreNowKeys m =
let expected = nub $ sort $ Map.elems m
actual = invertMap m
in expected === nub (sort $ fmap fst actual)
Since this property is still parametrically polymorphic, you'll have to add it to your test suite with a particular type, e.g.:
tests = [
testGroup "Sorting Group 1" [
testProperty "all values are now keys" (allValuesAreNowKeys :: Map String Int -> Property)]]
There are prettier ways to define lists of properties; that one is just the template used by the quickcheck-test-framework Stack template...

Using Filter that requires multiple Input - Haskell

I'm relatively new to Haskell, and have been trying to learn it for the past few weeks, but have been stuck on Filters and Predicates, which I was hoping to get help with understanding.
I have come across a problem whereby I have a list of tuples. Each tuple consists of a (songName, songArtist, saleQty) and am required to remove a tuple from that list based on the user inputting the songName and SongArtist.
When returning the results, I understand I can remove a tuple by using the Filter function when returning the results. I have been doing some reading on it using LYAH. Its taught me that I have to use a Predicate (which is another function) to filter through my results. This has caught me off guard as I learnt a Filter function has type (a -> Bool) -> [a] -> [a], which means my input for the Filter needs to to be a Boolean and my output for my Predicate needs to be Boolean so it can be fed to the Filter.
This is a problem, as to filter my results from the list I need to input the songName and songArtist (both of which are String types) to the predicate when recursively going through the results, and output the songName and songArtist to the Filter to let it know which exact tuple needs to be removed from the list.
Am I going about this the wrong way or is there a better way I could go about this?
I learnt a Filter function has type (a -> Bool) -> [a] -> [a]
The filter :: (a -> Bool) -> [a] -> [a] takes two parameters, a predicate with signature a -> Bool, and a list of items, and it returns a list of items that satisfy the predicate. So the predicate is the first parameter.
which means my input for the Filter needs to to be a Boolean.
No the first parameter has type a -> Bool, so it is a function that maps an item a to a Bool, so a predicate.
You can for example create a function that checks if both the songName and songTitle match with:
filterSales :: String -> String -> [(String, String, Int)] -> [(String, String, Int)]
filterSales artist title items = filter p items
where p (artist', title', _) = artist == artist' && title == title'
Here p is thus the predicate, a function that maps a 3-tuple to a boolean. The predicate p will return True for a 3-tuple if the first two items are equal to the artist and title respectively.
This is a second answer and the existing one is great, so I'll show my alternate take; after all, two explanations can't be worse than one, right?
What filter expects of you is a function that will tell it one thing - should I keep the given element in the resulting collection?
The type of that function is (a -> Bool), and that's what we call a predicate.
In your specific case, assuming
type SongEntry = (SongName, SongArtist, SaleQty)
It's gonna be a function of type SongEntry -> Bool. Now, there could be a lot of such functions... maybe you want more than 100 sales?
hasMoreThan100Sales :: SongEntry -> Bool
hasMoreThan100Sales (_, _, sales) = sales > 100
To use it:
filter hasMoreThan100Sales songs
That should be easy enough. What if we wanted more than n sales? This is where Haskell's curry-by-default really shines. We can add one additional parameter:
hasMoreThanNSales :: Int -> SongEntry -> Bool
Which we can also read and understand as Int -> (SongEntry -> Bool). The implementation is straighforward at this point:
hasMoreThanNSales n (_, _, sales) = sales > n
And crucially, to get our previous "100" function, we just need to apply it:
hasMoreThanNSales 100 :: SongEntry -> Bool
This has the type we need to use it with the filter:
filter (hasMoreThanNSales 100) songs
At this point, you should understand it well enough to write your own predicate that can be parametrized in any way you want.
Oh, and one more thing that might be confusing. hasMoreThan100Sales is a predicate. hasMoreThanNSales is not, until you apply it with a value (e.g. 100) - (hasMoreThanNSales 100) is a predicate.

Haskell accesing the sublist while filtering a list of a list

I'm fairly new to Haskell, and try to accomplish the following:
filter (((!!) subList (fromJust (elemIndex String [String]))) == String) [[string]]
I replaced the names with their types to make it easier to read. The problem is that i can't do subList, but the (!!) takes a list as argument. So how would i go about writing this?
edit:
I wrote the filtering condition seperately, which works, but the problem is still the same:
findGood :: [String] -> String -> [String] -> String -> Bool
but i still need to fill in all the values, though the first [String] is the sublist. All the other values can be entered..
Edit:
I solved it, what i needed to do was put the [String] last, and then i could leave it out in the filter
So
findGood :: String -> [String] -> String -> [String] -> Bool
filter (findGood a b c) [[String]]
Thats what works, and thats what I wanted. (not needing the D)
Given that you're wanting to compare money and check money > 500 it makes much more sense to store it as an Int not a String. Furthermore I would say storing each entry as a tuple and having a list of tuples makes more sense than using a list of lists (this is also required for the Int implementation of money as you can't have a list of different types of lists).
So the table would have type [(String, Int)].
filter goes through the list and checks each element against a condition. In this case the condition is so simple I wouldn't bother making it it's own function (unless you need to reuse it in lots of places).
When given a pair of type (String, Int) we just want to check if that second value is > 500. So the condition is simply snd row > 500 where row is the tuple we were given representing a row in the table.
This leaves us with:
filter (\row -> snd row > 500) table
Testing on [("Geoff", 600), ("Bill", 700), ("Bill Jr.", 10)] this gives [("Geoff", 600), ("Bill", 700)] as expected.

converting a list of string into a list of tuples in Haskell

I have a list of strings:
[" ix = index"," ctr = counter"," tbl = table"]
and I want to create a tuple from it like:
[("ix","index"),("ctr","counter"),("tbl","table")]
I even tried:
genTuple [] = []
genTuples (a:as)= do
i<-splitOn '=' a
genTuples as
return i
Any help would be appriciated
Thank you.
Haskell's type system is really expressive, so I suggest to think about the problem in terms of types. The advantage of this is that you can solve the problem 'top-down' and the whole program can be typechecked as you go, so you can catch all kinds of errors early on. The general approach is to incrementally divide the problem into smaller functions, each of which remaining undefined initially but with some plausible type.
What you want is a function (let's call it convert) which take a list of strings and generates a list of tuples, i.e.
convert :: [String] -> [(String, String)]
convert = undefined
It's clear that each string in the input list will need to be parsed into a 2-tuple of strings. However, it's possible that the parsing can fail - the sheer type String makes no guarantees that your input string is well formed. So your parse function maybe returns a tuple. We get:
parse :: String -> Maybe (String, String)
parse = undefined
We can immediately plug this into our convert function using mapMaybe:
convert :: [String] -> [(String, String)]
convert list = mapMaybe parse list
So far, so good - but parse is literally still undefined. Let's say that it should first verify that the input string is 'valid', and if it is - it splits it. So we'll need
valid :: String -> Bool
valid = undefined
split :: String -> (String, String)
split = undefined
Now we can define parse:
parse :: String -> Maybe (String, String)
parse s | valid s = Just (split s)
| otherwise = Nothing
What makes a string valid? Let's say it has to contain a = sign:
valid :: String -> Bool
valid s = '=' `elem` s
For splitting, we'll take all the characters up to the first = for the first tuple element, and the rest for the second. However, you probably want to trim leading/trailing whitespace as well, so we'll need another function. For now, let's make it a no-op
trim :: String -> String
trim = id
Using this, we can finally define
split :: String -> (String, String)
split s = (trim a, trim (tail b))
where
(a, b) = span (/= '=') s
Note that we can safely call tail here because we know that b is never empty because there's always a separator (that's what valid verified). Type-wise, it would've been nice to express this guarantee using a "non-empty string" but that may be a bit overengineered. :-)
Now, there are a lot of solutions to the problem, this is just one example (and there are ways to shorten the code using eta reduction or existing libraries). The main point I'm trying to get across is that Haskell's type system allows you to approach the problem in a way which is directed by types, which means the compiler helps you fleshing out a solution from the very beginning.
You can do it like this:
import Control.Monda
import Data.List
import Data.List.Split
map ((\[a,b] -> (a,b)) . splitOn "=" . filter (/=' ')) [" ix = index"," ctr = counter"," tbl = table"]

Searching through tuple of more than 2 elements

How can I search a tuple based on the first element or second or third?
I know how to search tuple of two but how do i do it for more than two?
type Stuff = (String, String, Int)
testStuff :: [Stuff]
testStuff = [
("beans","black",5),
("cod","fish",4),
("coke","diet",3)
]
How can I write a function that will search "Stuff" and return the "int" value?
e.g searchStuff "beans" should return 5.
Since you haven't provided your function for searching in a list of pairs, I'm going to assume that you used lookup. Lets focus on find for your new function. find can be found in Data.List (and a more general version in Data.Foldable) and has the following type:
find :: (a -> Bool) -> [a] -> Maybe a
Now, if you need to find something in a list of triples based on the first element, you could use
find (\(a,_,_) -> a == "beans") testStuff
However, this will leave you with a Maybe Stuff. But since Maybe is an instance of Functor, it is easy to change the result to Maybe Int (and is left as an exercise).
The Prelude defines lookup to handle searching a list of pairs. Here's the definition:
-- | 'lookup' #key assocs# looks up a key in an association list.
lookup :: (Eq a) => a -> [(a,b)] -> Maybe b
lookup _key [] = Nothing
lookup key ((x,y):xys)
| key == x = Just y
| otherwise = lookup key xys
Can you see how one would define a similar function to search a list of triples?

Resources