Reputation: 55
I have a type of Film as follows:
type Film = (String, String, Int, [Rating])
type Rating = (String, Int)
My aim, is to have a list of films in a database, like this:
myDatabase :: [Film]
myDatabase = [("Batman","Nolan",2012, [])]
And upon the function showFilms, it returns the entire list as a String value.
My code is as follows:
showFilms :: [Film] -> String
showFilms [] = []
showFilms (x:xs) = output: showFilms xs
where [[output]] = title ++ director ++ [(show year)] ++ [(show ratings)]
film = [film | (film) <- [x]]
title = [title | (title,director,year,ratings) <- film]
director = [director | (title,director,year,ratings) <- film]
year = [year | (title,director,year,ratings) <- film]
ratings = [ratings | (title,director,year,ratings) <- film]
It compiles on WinGHCi, but when i input anything other than an empty Database i get this error:
*** Exception: HaskellCW.hs:32:29-95: Irrefutable pattern failed for pattern [[output]]
Any help as to why this is happening, and how to fix it would be much appreciated.
I'm fairly new to this language, so apologies if it's not the most elegant way of doing it.
Thanks in advance.
Upvotes: 0
Views: 1609
Reputation: 16221
The problem is that title ++ director ++ [(show year)] ++ [(show ratings)]
evaluates to a list of strings, which is a list of lists of characters, but the pattern [[output]]
only matches if there is only one string in the list and that one string contains only one character.
It seems to me that what you want to do is turn x
into a string. Why not do it like this
showFilms :: [Film] -> String
showFilms [] = []
showFilms (x:xs) = output ++ showFilms xs
where output = title ++ director ++ (show year) ++ (show ratings)
(title, director, year, ratings) = x
Upvotes: 3
Reputation: 105876
Unless you want a specific format, the following code is enough, since String
and Int
are instances of Show
:
showFilms :: [Film] -> String
showFilms = show
Note that you can also read your database back from the string, since those types are also instances of Read
:
readFilms :: String -> [Film]
readFilms = read
If you want a specific format, better think about Film -> String
for a single film first, and map that function over your database:
showFilm :: Film -> String
showFilm (title, director, year, ratings)
= title ++ " " ++ director ++ " [" ++ (show year) ++ "] [" ++ (show ratings) ++ "]"
showFilms' :: [Film] -> String
showFilms' = unlines . map showFilm
Upvotes: 2