简体   繁体   English

Haskell的电影数据库

[英]Film database in Haskell

Currently trying to solve 2 main questions in my haskell program. 目前正在尝试解决我的haskell程序中的2个主要问题。

  1. display all films that a given user is a fan of 显示给定用户喜欢的所有电影
  2. display all the films of a given actor that were released during a particular period (ie between a given start year and end year) 显示在特定期间(即在给定的开始年份和结束年份之间)放映的给定演员的所有电影。

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. 数据库更大,但是出于空间原因,我省略了一些。

  • How do I now create the functions required to answer the 2 questions above using this database? 现在如何使用该数据库创建回答以上两个问题所需的功能?

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.

相关问题 电影项目的Filemaker数据库设计 - Filemaker Database design for Film project 无法解决此 SQL 查询涉及给定电影数据库的子查询 - Can't solve this SQL query involving subqueries for given film database 我如何从 mysql sakila 数据库中获得以下结果集:所有电影的列表以及该电影中每个演员的名字和名字 - How can I get the following result set from mysql sakila database: List of all the films with film name and name of every actor in that film 用于数据库抽象的惯用 haskell - Idiomatic haskell for database abstraction 是否有使用代数数据类型的Haskell数据库? - Is there a Haskell database using algebraic datatypes? Haskell在不更改代码的情况下删除数据库变量 - Haskell Removing database variable without changing code 从Haskell数据库获取列值 - Get column values from a Haskell Database 将Haskell与数据库后端一起用于“业务应用程序” - Using Haskell with a database backend for “business applications” Haskell可以假装是一个数据库吗?如果是的话,怎么样? - Can Haskell pretend to be a database, and if so, how? Haskell:在Persist.Sql中使用元组-数据库作为PersistSqlField - Haskell : Using Tuple in a Persist.Sql - Database as PersistSqlField
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM