Haskell中的电影数据库

时间:2013-04-03 13:44:25

标签: database list haskell

目前正在尝试解决我的haskell计划中的两个主要问题。

  1. 显示给定用户喜欢的所有电影
  2. 显示在演出期间发布的给定演员的所有电影 特定时期(即在给定的开始年份和结束年度之间)
  3. 这是我目前使用的示例数据库:

    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"])]    
    

    数据库要大得多,但由于空间原因我省略了一些。

    • 我现在如何使用此数据库创建回答上述2个问题所需的功能?

4 个答案:

答案 0 :(得分:1)

这是对你的第一个问题的一个非常简短的答案。这看起来像是家庭作业,所以你应该自己尝试解决第二个问题!

fan y = map (\(a,_,_,_) -> a) $ filter (\(_,_,_,a) -> elem y a) testDatabase

重要的部分是:

elem测试y是否是列表a的成员 - 即电影是否包含粉丝列表中的用户。

filter获取谓词和列表,并仅返回该列表中满足谓词的项目。

map接受一个函数和一个列表,并将该函数应用于列表。这用于仅提取电影的标题。

您应该能够使用类似的方法来回答第二个问题。

答案 1 :(得分:1)

这应该有效:

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
祝你好运!

答案 2 :(得分:0)

如果您将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] }):

Film

您的第一个问题表明您希望给定用户为Fan的{​​{1}}(而不是Film的标题):

fanOfFilms :: Fan -> Database -> [Film]
fanOfFilms fan = filter (elem fan . filmFans)

你的第二个问题可以用同样的方式解决,但谓词变得更复杂:

periodActorOfFilms :: Cast -> Year -> Year -> Database -> [Film]
periodActorOfFilms actor startYear endYear =
    filter $ \film -> and [ actor `elem` filmCast film
                          , startYear <= filmYear film
                          , endYear >= filmYear film
                          ]

答案 3 :(得分:0)

如果您使用以下类型声明,此解决方案将起作用。 代数类型更好地实现这些功能。

-- 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

作为额外功能,您使用以下内容首先检查风扇是否存在,然后如果返回值“”,系统将继续检索电影。但这是为了实现用户界面。

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                         = ""

这已经晚了一年,但希望对你所有的数学家来说仍然有用;)