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.
1 Answer 1
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.
concatMap
+filter
+map
. \$\endgroup\$