AlexJonBarry
AlexJonBarry

Reputation: 55

In Haskell, how to return items in a list as a String?

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

Answers (2)

Theodore Norvell
Theodore Norvell

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

Zeta
Zeta

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

Related Questions