Reputation: 1117
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
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
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