[Haskell-beginners] movie database
Daniel Fischer
daniel.is.fischer at web.de
Fri May 7 13:55:35 EDT 2010
On Friday 07 May 2010 18:55:57, Payan Peshraw wrote:
> Hi,
>
>
>
> I have got a database with movies added into it. What Im basically
> coding is:
>
>
>
> - add a new film to the database
> - display all the films
> - display all the films by a given director
> - display a list of user ratings (together with the users' names) for a
> given film - show the average overall rating for a given director
> - allow a given user to rate (or re-rate) a film (note that only the
> latest rating from the user should remain recorded) - display all the
> films from a given year, sorted in descending order of overall rating
>
> Now I want to allow a given user to rate or be able to re-rate a film.
> But the latest rating from the user should remain recorder tho..and also
> I want to display all the films that a given user likes (i.e. the films
> to which she has given a positive-valued rating). I have written the
> code for the user liking the film but it doesn't seem to work and i'm
> not sure what to do with that one eiher.
>
> Below is the coding that I've written so far, but i'm stuck on the last
> bit which I can't seem to code.
>
>
> type Director = String
> type Title = String
> type Year = Int
> type Mark = Int
> type Rating = (String, Int)
>
> type Film = (Title, Director, Year, [Rating])
Consider making Film an ADT,
data Film
= Film
{ title :: Title
, director :: Director
, year :: Year
, ratings :: [Rating]
}
, maybe also Rating:
type User = String
data Rating
= Rating
{ user :: User
, rating :: Mark
}
> type Database = [Film]
>
> testDatabase :: Database
> testDatabase = [("Casino Royale", "Martin Campbell", 2006,
> [("Garry",-8),("Dave", 0)]), ("Blade Runner", "Ridley Scott", 1982,
> [("Amy",5)]), ("The Fly", "David Cronenberg", 1986, [("Fred",7)])
> ]
>
> addFilm :: Database -> Title -> Director -> Year -> Database
> addFilm database title director year
> = (title, director, year, []): database
>
> displayFilms :: Database ->[(Title, Director, Year, Mark)]
> displayFilms [] = []
> displayFilms ((i, j, k, l):xs)
>
> |l == [] = (i, j, k, 0) : displayFilms xs
> |otherwise = (i, j, k, overallRating l) : displayFilms xs
>
> overallRating :: [Rating] -> Int
> overallRating rating = div (sum [j | (_,j) <- rating]) (length rating)
That gives an error for an empty list.
>
> filmsByDirector :: Database -> Director -> Database
> filmsByDirector [] filmDirector = []
> filmsByDirector((i, j, k, l):xs) filmDirector
>
> |j == filmDirector = (i, j, k, l) : filmsByDirector xs
> | filmDirector otherwise = filmsByDirector xs
> | filmDirector
>
> filmRating :: Database -> Title -> [Rating]
> filmRating [] filmRat = []
> filmRating ((i,j, k, l):xs) filmRat
>
> |i == filmRat = (l ++ filmRating xs filmRat)
> |otherwise = filmRating xs filmRat
>
> THIS DOESNT SEEM TO WORK?
> {-
> filmsLiked :: Database -> String -> Database
> filmsLiked [] user = []
> filmsLiked ((i,j,k,l):xs) user
>
> | == user = i ++ filmsLiked xs user
That should of course be "i : filmsLiked xs user" if the function should
return the list of titles of the films the user likes,
"(i,j,k,l) : filmsLiked xs user" if it should return a Database (as the
type signature says in accordance with the behaviour of filmsByDirector).
> |otherwise = filmsLiked xs user
>
> person :: [Rating] -> String -> Bool
> person [] userName = False
> person ((n, s):xs) userName
>
> |n == userName && s > 0 = True
> |otherwise = person xs userName
>
> -}
You have the function which tells you whether a user liked a film (more
precisely, whether a list of Ratings contains a positive rating from a
user). The name of that function is very inappropriate, though.
Use that to write
likes :: User -> Film -> Bool
likes user (t,d,y,rs) = ???
And then use that in filmsLiked,
filmsLiked :: Database -> User -> Database
filmsLiked (film : rest) user
| user `likes` film = ???
| otherwise = filmsLiked rest user
filmsLiked [] _ = []
>
> averageDirector :: Database -> Director -> Int
> averageDirector [] directorRating = 0
> averageDirector ((i,j,k,l):xs) directorRating
>
> |j == directorRating = (overallRating l) +
> | (averageDirector xs directorRating) otherwise =
> | averageDirector xs directorRating
>
> filmFromYear :: Database -> Year -> Database
> filmFromYear [] filmYear = []
> filmFromYear ((i,j,k,l):xs) filmYear
>
> |k == filmYear = (i,j,k,l) : filmFromYear xs
> | filmYear otherwise = filmFromYear xs filmYear
>
> rateFilm :: [Rating] -> Rating -> [Rating]
> rateFilm [] rating = rating:[]
> rateFilm ((user, rating):xs) (newUser, newRating)
>
> |newUser == user = ((newUser, newRating):xs)
> |otherwise = (user, rating) : (rateFilm xs (newUser,
> | newRating))
>
> Stuck on this bit..
> {-
> changeFilm :: Database -> Title -> [Rating] -> Database
> changeFilm .........
> -}
What is that supposed to do?
>
>
>
> Any help is appreciated..thank you!
Generally,
- the use of i, j, k, l as parameter names is bad. If you want to use one-
letter parameters, pick the initials of their meaning, (t, d, y, r) is in
this context much better. (title, director, year, ratings) still better.
- the argument order of your functions is irritating. It would be more
natural to have the Database as the last argument.
- the code could be much improved by
* using as-patterns, e.g.
filmsByDirector (film@(_,d,_,_) : rest) dir
| d == dir = film : filmsByDirector rest dir
| otherwise = filmsByDirector rest dir
* using functions like filter, e.g.
filmsByDirector db dir = filter (dir `isDirector`) db
where
isDirector name (_,d,_,_) = name == d
* using list-comprehensions, e.g.
filmsByDirector db dir = [film | film@(_,d,_,_) <- db, dir == d]
More information about the Beginners
mailing list