几个错误:
testDatabase :: Database
testDatabase = [("Casino Royale", ["Daniel Craig", "Eva Green", "Judi Dench"], 2006, ["Garry", "Dave", "Zoe", "Kevin", "Emma"]),
-- indentation should be consistent - this next line was too far left:
("Cowboys & Aliens", ["Harrison Ford", "Daniel Craig", "Olivia Wilde"], 2011, ["Bill", "Jo", "Garry", "Kevin", "Olga", "Liz"]),
("Catch Me If You Can", ["Leonardo DiCaprio", "Tom Hanks"], 2002, ["Zoe", "Heidi", "Jo", "Emma", "Liz", "Sam", "Olga", "Kevin", "Tim"])]
并且您忘记了]
该列表末尾的右括号。
displayAllFilms :: [Film] -> String -> String
displayAllFilms [] filmString = filmString
displayAllFilms ((title,cast,year,fans):films) filmString = displayAllFilms films (filmString ++ title ++ "\n" ++ (show cast) ++ "\n" ++ (show year) ++ "\n")
(Title cast year fans)
你的意思是在这里(title,cast,year,fans)
。
Haskell 区分大小写,大写字母表示Title
是构造函数,但您的意思是它是变量。因为你的Film
类型是一个元组,所以这里的逗号也需要是一个元组。
正确输出
现在这给了你输出
putStrLn $ displayAllFilms testDatabase "=========="
==========Casino Royale
["Daniel Craig","Eva Green","Judi Dench"]
2006
Cowboys & Aliens
["Harrison Ford","Daniel Craig","Olivia Wilde"]
2011
Catch Me If You Can
["Leonardo DiCaprio","Tom Hanks"]
2002
现在这与您所需的输出不匹配,
Casino Royale, Daniel Craig, Eva Green, Judi Dench, 2006, 5
因为有换行符而不是逗号,以及您不想要的括号。
listStuff:: [String] -> String -> String
listStuff strings separator = concat [string++separator| string <-strings]
在这里,我使用列表推导来制作最后带有分隔符的字符串列表,然后concat
将它们连接在一起。最后你会得到一个备用", "
的,但这没关系,因为我们需要一个介于演员和年份之间的人。
现在我们可以把它放在一起,length fans
用来显示粉丝的数量。
displayAllFilms' :: [Film] -> String -> String
displayAllFilms' [] filmString = filmString
displayAllFilms' ((title,cast,year,fans):films) filmString =
displayAllFilms' films (filmString ++ "\n" ++ title ++ ", " ++ listStuff cast ", " ++ (show year) ++ ", " ++ show (length fans))
测试结果为
>putStrLn $ displayAllFilms' testDatabase ""
Casino Royale, Daniel Craig, Eva Green, Judi Dench, 2006, 5
Cowboys & Aliens, Harrison Ford, Daniel Craig, Olivia Wilde, 2011, 6
Catch Me If You Can, Leonardo DiCaprio, Tom Hanks, 2002, 9
稍微清理一下代码
我认为displayAllFilms
不需要递归——我们可以重用listStuff
,但是有一个库函数可以做更多我们想要的事情。如果你在 hoogle 上搜索[String] -> String -> String
你会得到这些结果 http://www.haskell.org/hoogle/?hoogle=[String]+-%3E+String+-%3E+String 和第二个,intercalate
很方便:
> intercalate "_" ["Hello","Mum,","how","are","you?"]
"Hello_Mum,_how_are_you?"
你必须把
import Data.List
在代码的顶部使用它。所以现在我们可以做
commas :: [String] -> String
commas = intercalate ", "
所以我们可以显示一个单独的电影,然后用它来显示电影列表。
showFilm :: Film -> String
showFilm (title,cast,year,fans) = commas [title, commas cast, show year, show (length fans)]
我们可以写
showDatabase :: Database -> String
showDatabase fs = intercalate "\n" [showFilm f | f<-fs]
但这样做会更好
showDatabase :: Database -> String
showDatabase = unlines.map showFilm
因为你只想showFilm
在每一部电影上使用,然后unlines
这意味着intercalate "\n"
无论如何,但更容易看到。
> putStrLn $ showDatabase testDatabase
Casino Royale, Daniel Craig, Eva Green, Judi Dench, 2006, 5
Cowboys & Aliens, Harrison Ford, Daniel Craig, Olivia Wilde, 2011, 6
Catch Me If You Can, Leonardo DiCaprio, Tom Hanks, 2002, 9