0

I am trying to change the Film type to a data type so it will make it easier to order and save and load to a file, I am having problems matching the functions up with the right arguments, it was a lot easier working with the types.

type Rating = (String, Int)
--type Film = (String, String, Int, [Rating])
data Film = Film String String Int [Rating]
         deriving (Show,Ord,Eq, Read)

testDatabase :: [Film]
testDatabase = []

testFilm = ("Test","Test",2012,[("Test",8),("Test",5)])

saveToFile :: IO ()
saveToFile = do
    putStrLn "Enter the output filename: "
    name <- getLine
    writeFile name (show testDatabase)
    putStrLn "Done"

loadFromFile :: IO ()
loadFromFile = do
    putStrLn "Enter the input filename: "
    name <- getLine
    contents <- readFile name
    let testDatabase = length contents `seq` (read contents :: [Film])
    putStrLn formatDatabase
    putStrLn "Done"


average xs = realToFrac (sum xs) / genericLength xs 

addFilm :: String -> String -> Int -> [Film] -> [Film]
addFilm title director year db = db ++ Film title director year []

filmsByDirector :: String -> [Film]
filmsByDirector name = filter (\(a,_,_,_) -> a == name) testDatabase

filmsByRating :: Float -> [Film]
filmsByRating rating = filter (\(_,_,_,a) -> filmRating a > rating) testDatabase

filmsByYear :: Int -> [Film]
filmsByYear year = filter (\(_,_,a,_) -> a == year) testDatabase

filmRating :: [(String,Int)] -> Float
filmRating ratings = average (map snd ratings)

formatString :: Film -> String
formatString (dir, film, year, rat) = printf "\n\nDirector: %s \nFilm Name: %s \nYear: %s \nRating: %4.2f" (show dir) (show film) (show year) (filmRating rat)

formattedByYear :: Int -> String
formattedByYear year = concatMap formatString $ filmsByYear year

formattedByDirector :: String -> String
formattedByDirector dir = concatMap formatString $ filmsByDirector dir

formatDatabase = concatMap formatString $ testDatabase
2
  • 1
    Film is a datatype in the code there, you'll have to provide more details. (Also, you might be interested in record syntax) Commented May 1, 2012 at 11:02
  • file.hs:43:40: Couldn't match expected type [Film]' with actual type Film' In the return type of a call of Film' In the second argument of (++)', namely `Film title director year []' In the expression: db ++ Film title director year [] Commented May 1, 2012 at 11:03

1 Answer 1

7

There isn't much to necessarily change, instead of

filmsByDirector name = filter (\(a,_,_,_) -> a == name) testDatabase

where you use the (,,,) constructor for the pattern, you use the Film constructor

filmsByDirector name = filter (\(Film a _ _ _) -> a == name) testDatabase

and similarly for the other functions.

However, it's much more convenient to use named-field (or record) syntax and define

data Film = Film { director, title :: String, year :: Int, ratings :: [Rating] }

and then the function would be simply

filmsByDirector name = filter ((name ==) . director) testDatabase

or, if you're uncomfortable with point-free style

filmsByDirector name = filter (\f -> director f == name) testDatabase

For the error regarding Film vs [Film] in addFilm, you have to wrap the last film into [],

addFilm title director year db = db ++ [Film title director year []]
Sign up to request clarification or add additional context in comments.

5 Comments

Thanks! How would I go about receiving film as a variable? Previously I could seperate the Film in to different variables, would I need to do Film -> String -> String -> Int -> [Rating] -> String ?
I'm not sure I understand. If you want to get e.g. the title (second String), with record syntax, you already have the selector title :: Film -> String. Without record syntax, it'd be title (Film _ t _ _) = t, just like with the tuple it was title (_,t,_,_) = t.
Sorry I wasn't clear enough. formatString dir film year rat = printf "\n\nDirector: %s \nFilm Name: %s \nYear: %s \nRating: %4.2f" (show dir) (show film) (show year) (filmRating rat) I cannot access dir / film / year or rat directly in the same way as I did before, that's why I asked if I needed to change the formal parameters.
Solved: formatString :: Film -> String formatString (Film dir film year rat) = printf "\n\nDirector: %s \nFilm Name: %s \nYear: %s \nRating: %4.2f" (show dir) (show film) (show year) (filmRating rat)
For example that. But I'd recommend to not use show year, rather use the %d format in the printf format string.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.