[英]Film database in Haskell
Currently trying to solve 2 main questions in my haskell program. 目前正在尝试解决我的haskell程序中的2个主要问题。
This is the sample database I am currently using: 这是我当前正在使用的示例数据库:
type Title = String
type Cast = String
type Year = Int
type Fans = String
type Film = (Title, [Cast], Year, [Fans])
type Database = [Film]
testDatabase :: Database
testDatabase = [("Casino Royale", ["Daniel Craig", "Eva Green", "Judi Dench"], 2006, ["Garry", "Dave", "Zoe", "Kevin", "Emma"]),
("Cowboys & Aliens", ["Harrison Ford", "Daniel Craig", "Olivia Wilde"], 2011, ["Bill", "Jo", "Garry", "Kevin", "Olga", "Liz"]),
("Catch Me If You Can", ["Leonardo DiCaprio", "Tom Hanks"], 2002, ["Zoe", "Heidi", "Jo", "Emma", "Liz", "Sam", "Olga", "Kevin", "Tim"])]
The database is much bigger but for space reasons I omitted some of this. 数据库更大,但是出于空间原因,我省略了一些。
Here's a very short answer to your first question. 这是对第一个问题的简短回答。 This looks like homework, so you should try to solve the second by yourself!
这看起来像作业,所以您应该尝试自己解决第二个问题!
fan y = map (\(a,_,_,_) -> a) $ filter (\(_,_,_,a) -> elem y a) testDatabase
The important parts are: 重要的部分是:
elem
tests whether y
is a member of list a
- ie whether the film contains the user in its list of fans. elem
测试y
是否是列表a
的成员-即电影是否在其粉丝列表中包含用户。
filter
takes a predicate and a list, and returns only the items in that list satisfying the predicate. filter
接受一个谓词和一个列表,并仅返回该列表中满足该谓词的项目。
map
takes a function and a list, and applies that function over the list. map
接受一个函数和一个列表,然后将该函数应用于列表。 This is used to extract only the title of the film. 这仅用于提取电影的标题。
You should be able to use a similar approach to answer the second question. 您应该能够使用类似的方法来回答第二个问题。
This should work: 这应该工作:
type Title = String
type Actor = String
type Cast = [Actor]
type Year = Int
type Fan = String
type Fans = [Fan]
type Period = (Year, Year)
type Film = (Title, Cast, Year, Fans)
type Database = [Film]
testDatabase :: Database
testDatabase = [("Casino Royale", ["Daniel Craig", "Eva Green", "Judi Dench"], 2006, ["Garry", "Dave", "Zoe", "Kevin", "Emma"]),
("Cowboys & Aliens", ["Harrison Ford", "Daniel Craig", "Olivia Wilde"], 2011, ["Bill", "Jo", "Garry", "Kevin", "Olga", "Liz"]),
("Catch Me If You Can", ["Leonardo DiCaprio", "Tom Hanks"], 2002, ["Zoe", "Heidi", "Jo", "Emma", "Liz", "Sam", "Olga", "Kevin", "Tim"])]
inCast :: Actor -> Film -> Bool
inCast givenActor (_, cast, _, _) = any (\actor -> actor == givenActor) cast
inPeriod :: Period -> Film -> Bool
inPeriod (periodStart, periodEnd) (_, _, year, _) = periodStart <= year && year <= periodEnd
inCastAndPeriod :: Actor -> Period -> Film -> Bool
inCastAndPeriod actor period film = inCast actor film && inPeriod period film
isFan :: Fan -> Film -> Bool
isFan givenFan (_, _, _, fans) = any (\fan -> fan == givenFan) fans
allFilmsThatAGivenUserIsAFanOf :: Fan -> [Film]
allFilmsThatAGivenUserIsAFanOf givenFan = filter (isFan givenFan) testDatabase
allTheFilmsOfAGivenActorThatWereReleasedDuringAParticularPeriod :: Actor -> Period -> [Film]
allTheFilmsOfAGivenActorThatWereReleasedDuringAParticularPeriod givenActor givenPeriod = filter (inCastAndPeriod givenActor givenPeriod) testDatabase
Good luck! 祝好运!
If you declare your Film
type as a record, you will get field accessors for free, which will make the filters easier to read (also, isn't Fans
a single Fan
?): 如果您将
Film
类型声明为记录,您将免费获得现场访问者,这将使过滤器更易于阅读(而且, Fans
不是一个Fan
吗?):
type Title = String
type Cast = String
type Year = Int
type Fan = String
data Film = Film { filmTitle :: Title
, filmCast :: [Cast]
, filmYear :: Year
, filmFans :: [Fan]
}
type Database = [Film]
Your 1st problem states that you want the Film
s of which a given user is a Fan
(not the titles of the Film
s): 你的第一个问题,说你想要的
Film
S的给定的用户是一个Fan
(不的标题Film
S):
fanOfFilms :: Fan -> Database -> [Film]
fanOfFilms fan = filter (elem fan . filmFans)
Your 2nd problem can be solved in the same manner, but the predicate becomes more complicated: 您的第二个问题可以用相同的方式解决,但谓词变得更加复杂:
periodActorOfFilms :: Cast -> Year -> Year -> Database -> [Film]
periodActorOfFilms actor startYear endYear =
filter $ \film -> and [ actor `elem` filmCast film
, startYear <= filmYear film
, endYear >= filmYear film
]
This solution works if you use the following type declarations. 如果使用以下类型声明,则此解决方案有效。 Algebraic type are much better to implement such functions.
代数类型更好地实现了此类功能。
-- Types
type Title = String
type Actor = String
type Year = Int
type Fan = String
-- Film type
data Film = Film Title [Actor] Year [Fan]
deriving (Eq,Ord,Show,Read)
-- converts a list of strings to string through recursion and pattern matching.
displayListAsString :: [String] -> String
displayListAsString [] = ""
displayListAsString (x:[]) = x ++ displayListAsString []
displayListAsString (x:xs) = x ++ ", " ++ displayListAsString xs
-- Give all films that a particular user is a fan of.
isFanOfMovies :: Fan -> [Film] -> String
isFanOfMovies fanName [] = "No Database provided."
isFanOfMovies fanName movieDB = moviesAsString $ isFanOf fanName movieDB
-- filters through the database to find the films which a particular user is a fan of.
isFanOf :: Fan -> [Film] -> [Film]
isFanOf fanName = filter (\(Film _ _ _ fans) -> elem fanName fans)
-- displays a movie as well formatted string
movieAsString :: Film -> String
movieAsString (Film title cast year fans) = "\nTitle: " ++ title ++ "\n Cast: " ++
(displayListAsString cast) ++ "\n Year: " ++ show year ++
"\n Fans: " ++ show (length fans)
-- Gives all films in the database (if database passed through directly)
moviesAsString :: [Film] -> String
moviesAsString movieDB = (unlines.map movieAsString) movieDB
As an extra function, you use the following to first check if the fan exists and then if the value "" is returned, then the system will proceed with retrieving the films. 作为一项附加功能,您可以使用以下内容首先检查风扇是否存在,然后如果返回值“”,则系统将继续获取胶片。 But this is for when you want to implement User Interface.
但这是当您要实现用户界面时使用的。
fanFilms (fanName, database) = do
let fan = fanExists fanName database
if fan == ""
then do
putStrLn "\nDisplaying all the films you're a fan of below:"
putStrLn $ isFanOfMovies fanName database
return (fanName, database)
else do
putStrLn "No Results Found.\n"
putStrLn $ fanExists fanName database
return (fanName, database)
-- This can be used to check if the fan exists.
fanExists :: Fan -> [Film] -> String
fanExists fanName movieDB
| isFanOf fanName movieDB == [] = "No movies you are fan of."
| otherwise = ""
It's a year late but hopefully still helpful with all you mathfun lot ;) 已经晚了一年,但希望对您所有的mathfun都有用;)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.