# List of tuples generated through list comprehension

The function returns a list of tuples which is generated through list comprehension:

getUserRatings :: String -> [Film] -> [(String,Int)]
getUserRatings search database = [(title,rate) | (Film title _ _ ratings) <- database, (user,rate) <- ratings, search == user]


Film is defined as:

type Rating = (String, Int)
data Film = Film {  title,director :: String,
year :: Int,
ratings :: [Rating] } deriving (Read,Show)


such that a database is:

testDatabase :: [Film]
testDatabase = [(Film "Blade Runner" "Ridley Scott" 1982 [("Amy",5),("Bill",8),("Ian",7),("Kevin",9),("Emma",4),("Sam",7),("Megan",4)])]


The function getUserRatings takes in a the users name and the database, searches the ratings in the database, then compiles the the tuple so that its in the format of:

film name (String), user rating (Int)

How might I write this more efficiently using higher order functions? I've attempted a few times but to no success using filters and maps; I don't know whether to post those attempts here or not. So I won't until advised otherwise.

• "How might I write this more efficiently using higher order functions?" More efficiently or more readable? Your current version isn't that much different from concatMap + filter + map. – Zeta Feb 23 '16 at 21:03
• @Zeta readable is probably better in my case. Thanks for the idea! – Jackson Jacob Feb 23 '16 at 22:18

Using high-order functions is not much readable:

userRatings search = concatMap (\film ->
map ((title film,) . snd)
$filter ((==search) . fst)$ ratings film)


You need {-# LANGUAGE TupleSections #-} to be able to write (title film,).

Another useful extension is NamedFieldPuns.

getUserRatings search database
= [ (title,rate)
| Film{title, ratings} <- database
, (user,rate) <- ratings
, search == user
]


Writing Film{title, ratings} instead of Film title _ _ ratings is not only a bit shorter, it also allows you to change/reorder fields in Film without updating getUserRatings.

Btw, in my opinion, splitting getUserRatings in several lines adds more readability than rewriting it somehow.