CS 119 Lab 6 – Lists
Objectives
Perform the following tasks in the order given.
You will write a portion of this system. The database will be a list of movie records. We will need a way of searching through the list in various ways. We will also need a way of programming the search using patterns on the user's queries.
Let's start by building the database. We will define our types for building a movie record:
type Title = String
type Director = String
type Year = Int
type Actor = String
type Actors = [Actor]type Movie = (Title, Director, Year, Actors)
Note that we have a list of actors and that the movie record is a tuple containing the information in a given order. Our movie database will simply be a list of type Movie. Here is a database with just two movie records:
movieDB :: [Movie]
movieDB = [ ("Amarcord",
"Federico Fellini",
1974,
["Magali Noel", "Bruno Zanin", "Pupella Maggio", "Armando Drancia"]),
("The Godfather",
"Francis Ford Coppola",
1972,
["Marlon Brando", "Al Pacino","James Caan", "Robert Duvall","Diane Keaton"])
]
We will also need selector functions:
movieTitle :: Movie -> Title
movieTitle (t,_,_,_) = tmovieDirector :: Movie -> Director
movieDirector (_,d,_,_) = dmovieYearMade :: Movie -> Year
movieYearMade (_,_,y,_) = ymovieActors :: Movie -> Actors
movieActors (_,_,_,a) = a
> filter f movieDB where f movie = (movieYearMade movie) == 1974
This will only keep those movies that were made in 1974. Try it out.
| Assignment: Write functions which will search for movies in a given year, by a given director, or containing a given actor: moviesMadeInYear :: Year -> [Movie] -> [Movie] moviesDirectedBy :: Director -> [Movie] -> [Movie] moviesWithActor :: Actor -> [Movie] -> [Movie]
For moviesWithActor, you will want
to check if a certain String is contained in the list of
actors. The function elem :: a -> [a] -> Bool
will do this. > moviesDirectedBy "Francis Ford Coppola" movieDB > moviesWithActor "Al Pacino" movieDB |
| Assignment: Write function titlesOfMoviesSatisfying :: (Movie->Bool) -> [Movie] -> [Title] which returns the list of titles satisfying the given predicate. For example > titlesOfMoviesSatisfying f movieDB where f movie = (movieYearMade movie) == 1974 Hint: Use the higher order function map. |
| Assignment: Write function moviesSatisfying :: (Movie->Bool) ->(Movie->a) -> [Movie] -> [a] which uses a selector to determine which attribute to display. For example > moviesSatisfying f movieTitle movieDB where f movie = (movieYearMade movie) == 1974
|
So if we match that pattern, we have a title matching the "..." wild card. This title is the argument to an anonymous function which performs the moviesSatisfying search using the filter (\m-> title == (movieTitle m)), to find all movies, m, with that given title, and then maps the function movieDirector to extract the director's name from that movie.
To make the answerByPattern function work we need to write matches and substInMatch. The function matches is of type [String]->[String]->Bool. It takes a list of words making up the pattern and a list of words making up the query and returns whether or not the query matches the pattern. Clearly a word in the pattern will have to exactly match the corresponding word in the query. The wild card "..." will match all the remaining words in the query. Here is the code for matches:
matches :: [String] -> [String] -> Bool
matches [][] = True
matches _ [] = False
matches ("..." : ps) q = True
matches (p : ps) (q : qs) = p == q && matches ps qs
The function substInMatch is similar in that it takes two lists of the pattern and query. However it is called only when we already know that the two lists match. It returns a list of the substitutions for the wild cards in the pattern that will make it match the query. For example:
> substInMatch ["foo", "..."] ["foo","bar","baz"]
[["bar","baz"]]
| Assignment: Write function substInMatch :: [String]->[String]->[[String]] Be sure to return a list containing the list of symbols matched by the "..." wild card. Note: We will later add additional wild cards to our patterns so that we may have multiple items in the list later on. |
> queryLoop
Who is the director of The Godfather
Francis Ford Coppola
Try it out.
| Assignment: Add another pattern of the form "Who acted in ..." to the patternActionList with its corresponding action. Hint: Since the movieActors selector will return [String] rather than String you will need to use the function listToString to convert this to a single String. Therefore use listToString.movieActors as the selector. The "." here is function composition. It performs the movieActors function and then performs listToString on the result. |
What movies were made in 1974
What movie was made in 1972
The pattern can be written as
"What ( movie movies ) ( was were ) made in _ "
We have extended our pattern language in two ways.
The "_" wild card matches exactly one word and it need not occur at the end
of the pattern as the "..." does. The "( )" wild card gives a
list of words that may match. So ( movie movies ) can match either the
word "movie" or the word "movies".
Here is matches extended for the list wild card:
matches :: [String] -> [String] -> Bool
matches [] [] = True
matches _ [] = False
matches ("..." : ps) q = True
matches ("(" : ps) (q : qs) = elem q (makeList ps) && matches (restPattern ps) qs
matches (p : ps) (q : qs) = p == q && matches ps qs
The pattern,
matches ("(" : ps) (q : qs),
sees that we are starting a list. We use
the function makeList to get the list of items up to the closing ")"
and check to see if the first word in the query is contained in that list.
The function restPattern returns the rest of the pattern after the
")" so that we can continue checking for a match after the list.
| Assignment: Extend matches to check for the "_" wild card. Remember that this matches a single word. Also there can be more than one "_" in a pattern and it need not be at the end of the pattern. |
| Assignment: Extend substInMatch to account for both of these new wild cards. It should return a list of substitutions, one for each wild card. |
("What ( movie movies ) ( was were ) made in _",
(\[noun,verb,year]-> moviesSatisfying (\m-> (stringToNum year) == (movieYearMade m))
movieTitle
movieDB))
Note that the action functions takes a list with three values for the three substitutions into the wild cards. It only uses the last substitution value, however. The function stringToNum converts the year from a String to and Int.
| Assignment: Add a pattern/action pair for the pattern: "What ( movie movies ) ( was were ) made between _ and _" |
| Assignment: Add a pattern/action pair for the pattern: "What ( movie movies ) ( was were ) made ( before after since ) _" |