Aserian
Aserian

Reputation: 1117

Haskell - How do I obtain the elements of a list within a list of pairs?

I have a structure

type MyDatabase = [ (String, [String]) ]

Given the first string, I would like to go through the database and find the matching term, then return the list accompanying it.

I have

lookup :: MyDatabase -> String -> [String]
lookup dataBase str = [ list | (label, [list]) <- dataBase, str == label ]

This is returning an empty list every time.

Upvotes: 1

Views: 291

Answers (2)

Will Ness
Will Ness

Reputation: 71065

A little tweak is needed to what you have:

lookup :: MyDatabase -> String -> [String]
-- lookup ...       = [ list | (label, [list]) <- dataBase, str == label ]
lookup dataBase str = [ s    | (label,  list ) <- dataBase, str == label 
                             , s <- list ]

If you have duplicate entries in your database under the same label, you will get all their values collected together in one list of strings, as per your type signature.

If you want only the first matching entry, you take just the first matching entry, and open it up with concat:

lookup dataBase str = concat . take 1 $
                      [ list | (label,  list ) <- dataBase, str == label]

Upvotes: 3

bheklilr
bheklilr

Reputation: 54058

You almost have the list comprehension right, and this would return something if you had the database [("foo", ["bar"])] and you tried lookup [("foo", ["bar"])] "foo". It wouldn't work if your database was [("foo", ["bar", "baz"])]. This is because you have pattern-matched on elements in the database that have only one element as their associated list of strings, so it doesn't work if a key has no associated elements or if it has many associated elements. You can fix this easily by changing it to (label, list) <- dataBase.

Additionally, you could instead use the lookup function that is built in to Prelude which has the type

lookup :: Eq a => a -> [(a, b)] -> Maybe b

Then you could specialize it for your type as

dbLookup :: MyDatabase -> String -> Maybe [String]
dbLookup dataBase str = lookup str dataBase
-- Or just
-- dbLookup = flip lookup
-- Or just
-- dbLookup :: String -> MyDatabase -> Maybe [String]
-- dbLookup = lookup

Upvotes: 4

Related Questions