haskell вводит / выводит ошибку при вызове функции
Я создал базу данных фильмов и функции, связанные с базой данных.
Сейчас я создаю демонстрационную функцию, где она дает результаты конкретных функций, выполняемых при нажатии числа в ghci. Например, когда набирается demo 2, он показывает все фильмы в базе данных.
Мне удалось создать большинство демонстрационных функций, но у меня проблемы с 3 из них, и они продолжают отображаться с ошибками. Я прокомментировал те, которые не работают и нуждаются в помощи, чтобы понять, в чем проблема.
Я включил все функции, которые я создал, с помощью демонстрационной функции ниже.
import Data.List
import Text.Printf
import Data.Ord
import Data.Char
type Rating = (String, Int)
type Title = String
type Director = String
type Year = Int
type Film = (Title, Director, Year,[Rating])
testDatabase :: [Film]
testDatabase = [("Blade Runner","Ridley Scott",1982,[("Amy",6), ("Bill",9), ("Ian",7), ("Kevin",9), ("Emma",4), ("Sam",5), ("Megan",4)]),
("The Fly","David Cronenberg",1986,[("Megan",4), ("Fred",7), ("Chris",5), ("Ian",0), ("Amy",5)]),
("Psycho","Alfred Hitchcock",1960,[("Bill",4), ("Jo",4), ("Garry",8), ("Kevin",7), ("Olga",8), ("Liz",10), ("Ian",9)]),
("Body Of Lies","Ridley Scott",2008,[("Sam",3), ("Neal",7), ("Kevin",2), ("Chris",5), ("Olga",6)]),
("Avatar","James Cameron",2009,[("Olga",2), ("Wally",8), ("Megan",9), ("Tim",5), ("Zoe",8), ("Emma",3)]),
("Titanic","James Cameron",1997,[("Zoe",7), ("Amy",2), ("Emma",5), ("Heidi",3), ("Jo",8), ("Megan",5), ("Olga",7), ("Tim",10)]),
("The Departed","Martin Scorsese",2006,[("Heidi",2), ("Jo",8), ("Megan",5), ("Tim",2), ("Fred",5)]),
("Aliens","Ridley Scott",1986,[("Fred",8), ("Dave",6), ("Amy",10), ("Bill",7), ("Wally",2), ("Zoe",5)]),
("Prometheus","Ridley Scott",2012,[("Garry",3), ("Chris",4), ("Emma",5), ("Bill",1), ("Dave",3)]),
("E.T. The Extra-Terrestrial","Steven Spielberg",1982,[("Ian",7), ("Amy",2), ("Emma",7), ("Sam",8), ("Wally",5), ("Zoe",6)]),
("The Birds","Alfred Hitchcock",1963,[("Garry",7), ("Kevin",9), ("Olga",4), ("Tim",7), ("Wally",3)]),
("Goodfellas","Martin Scorsese",1990,[("Emma",7), ("Sam",9), ("Wally",5), ("Dave",3)]),
("The Shawshank Redemption","Frank Darabont",1994,[("Jo",8), ("Sam",10), ("Zoe",3), ("Dave",7), ("Emma",3), ("Garry",10), ("Kevin",7)]),
("Gladiator","Ridley Scott",2000,[("Garry",7), ("Ian",4), ("Neal",6), ("Wally",3), ("Emma",4)]),
("The Green Mile","Frank Darabont",1999,[("Sam",3), ("Zoe",4), ("Dave",8), ("Wally",5), ("Jo",5)]),
("True Lies","James Cameron",1994,[("Dave",3), ("Kevin",4), ("Jo",0)]),
("Minority Report","Steven Spielberg",2002,[("Dave",5), ("Garry",6), ("Megan",2), ("Sam",7), ("Wally",8)]),
("The Wolf of Wall Street","Martin Scorsese",2013,[("Dave",6), ("Garry",6), ("Megan",0), ("Sam",4)]),
("War Horse","Steven Spielberg",2011,[("Dave",6), ("Garry",6), ("Megan",3), ("Sam",7), ("Wally",8), ("Zoe",8)]),
("Lincoln","Steven Spielberg",2012,[("Ian",3), ("Sam",7), ("Wally",3), ("Zoe",4), ("Liz",7), ("Megan",4)]),
("Vertigo","Alfred Hitchcock",1958,[("Bill",7), ("Emma",5), ("Zoe",9), ("Olga",6), ("Tim",10)]),
("The Terminal","Steven Spielberg",2004,[("Olga",3), ("Heidi",8), ("Bill",2), ("Sam",6), ("Garry",8)]),
("Jaws","Steven Spielberg",1975,[("Fred",3), ("Garry",0), ("Jo",3), ("Neal",9), ("Emma",7)]),
("Hugo","Martin Scorsese",2011,[("Sam",4), ("Wally",3), ("Zoe",4), ("Liz",7)])]
------------------------------------------------------------
-----------------FUNCTIONAL CODE----------------------------
------------------------------------------------------------
--when adding need to be addFilm string string int and the list name called testDatabase
addFilm :: String -> String -> Int -> [Film] -> [Film]
addFilm title director year database = (title, director, year, []) : database
--Some functions needed later on:
averageFilmRating :: [(String,Int)] -> Float
averageFilmRating ratings
= (fromIntegral(sum $ map snd ratings)) / (fromIntegral(length ratings))
--Formats the films for decimal, gives average rating of films instead of all users ratings.
formatFilmOutput :: Film -> String
formatFilmOutput (title, director, year, rating)
= printf "%s by %s. Year: %d, Average Rating: %.1f" (title) (director) (year) (averageFilmRating rating)
--Shows all films in the database
displayAllFilm :: [String]
displayAllFilm = map formatFilmOutput testDatabase
--Shows films by director name
displayByDirector :: String -> [Film]
displayByDirector name
= filter(\(_,director,_,_) -> director == name) testDatabase
--Gives the average of directors films
directorAverage :: String -> Float
directorAverage dir
= averageFilmRating [rating | (title, director, year, ratings) <- displayByDirector dir, rating <- ratings]
--These two functions give the films rated of average 6 or over
filmsRated :: Int -> [Film]
filmsRated rating
= filter(\(_,_,_,a) -> averageFilmRating a >= fromIntegral rating) testDatabase
filmsaveragesix = filmsRated 6
--Shows what films the user has rated.
userRatedFilms :: String -> [Film]
userRatedFilms username
= filter ((username `elem`) . (\(_,_,_,xs) -> map fst xs)) testDatabase
-- Allows user to rate or re-rate film.
databaseNoFilm:: [Film] -> Title -> [Film]
databaseNoFilm database t = [(title, director, year, ratings) | (title, director, year, ratings) <- database, title /= t]
rateFilm :: [Film] -> Title -> Rating -> [Film]
rateFilm database findtitle (u, r) = databaseNoFilm database findtitle ++ [(title,director,year,(u, r):[(username,rtg) | (username,rtg) <- ratings, username /= u]) | (title, director, year, ratings) <- database, title == findtitle]
--Displays films by year in descending order of rating
filmsByYear :: Int -> [Film]
filmsByYear year = sortFilms $ filter(\(_,_,yr,_) -> yr >= year) testDatabase
sortFilms :: [Film] -> [Film]
sortFilms = sortBy $ flip $ comparing averageFilmRating'
where
averageFilmRating' (_,_,_,rs) = averageFilmRating rs
------------------------------------------------------------
-----------------DEMO FUNCTION------------------------------
------------------------------------------------------------
demo :: Int -> IO ()
demo choice = do
case choice of
-- 1 -> do
-- putStrLn addFilm "Gravity" "Alfonso Cuaron" 2013 testDatabase
2 -> do
putStrLn (unlines displayAllFilm)
3 -> do
putStrLn (unlines (map formatFilmOutput(displayByDirector "James Cameron")))
4 -> do
putStrLn (unlines (map formatFilmOutput(filmsaveragesix)))
-- Get the director average of James Cameron
-- 5 -> do
-- putStrLn (directorAverage "James Cameron")
6 -> do
putStrLn (unlines (map formatFilmOutput(userRatedFilms "Zoe")))
-- all films after Zoe rates "Jaws" 8
-- 7 -> do
-- putStrLn rateFilm testDatabase "Jaws" ("Zoe", 8)
-- 77 all films after Zoe rates "Vertigo" 3
8 -> do
putStrLn (unlines (map formatFilmOutput(filmsByYear 2009)))
Проблема здесь связана с демонстрационными функциями, которые были закомментированы. Когда комментарий и запуск не выполнен, ошибка для демонстрации 1 относится к:
Couldn't match type `String -> String -> Int -> [Film] -> [Film]'
with `[Char]'
Expected type: String
Actual type: String -> String -> Int -> [Film] -> [Film]
In the first argument of `putStrLn', namely `addFilm'
In a stmt of a 'do' block:
putStrLn addFilm "Gravity" "Alfonso Cuaron" 2013 testDatabase
In the expression:
do { putStrLn
addFilm "Gravity" "Alfonso Cuaron" 2013 testDatabase }
Это аналогичная ошибка для остальных закомментированных демонстрационных функций
1 ответ
Проблема, с которой вы столкнулись, связана с линией
putStrLn addFilm "Gravity" "Alfonso Cuaron" 2013 testDatabase
Для компилятора это выглядит так, как будто вы пытаетесь применить 5 аргументов к putStrLn
, которая является функцией, которая принимает только 1 аргумент, следовательно, ошибка компилятора. Если бы вы должны были сделать
putStrLn (addFilm "Gravity" "Alfonso Cuaron" 2013 testDatabase)
Или эквивалентно (и красивее)
putStrLn $ addFilm "Gravity" "Alfonso Cuaron" 2013 testDatabase
Затем вы применяете 4 аргумента к addFilm
затем применяя этот результат к putStrLn
, Это все еще не скомпилируется, потому что addFilm
возвращает список Film
с не String
который является то, что putStrLn
надеется. Вы можете вместо этого использовать print
, который определяется как
print :: Show a => a -> IO ()
print x = putStrLn $ show x
Или вы могли бы использовать свой formatFilmOutput
функция:
putStrLn $ unlines $ map formatFilmOutput $ addFilm "Gravity" ...
а также unlines
преобразует список строк в одну строку, соединенную новыми строками.
Если вам интересно, что $
оператор, это буквально определяется как
($) :: (a -> b) -> a -> b
($) = id
infixr 0 $
Важной частью определения является infixr 0 $
линия. Это означает, что это правильно ассоциативно с фиксированностью 0
, который является самым низким приоритетом. Приложение функции имеет приоритет 9
это означает, что он всегда имеет приоритет над операторами, поэтому
add1 x * 2
Всегда так же, как
(add1 x) * 2
$
Оператор просто выступает в качестве альтернативы скобкам. Вы можете использовать его как
f $ g $ h $ i $ j $ k $ l $ m x
-- f through m are functions of one argument
Какие средства применяются x
в m
затем примените это к l
затем k
затем j
и так далее, или вы могли бы написать это как
f (g (h (i (j (k (l (m x)))))))
Который не весело, чтобы сбалансировать скобки для. Это работает только для применения последнего аргумента к функции, а не для любого из средних. Так
add = (+)
add $ 1 + 2 $ 3 + 4
не сработает, разбирает как
add (1 + 2 (3 + 4))
add (3 (7))
add (3 7)
Что просто не имеет смысла.