-1

鉴于Haskell中的数据库,我正在努力显示信息并将它们格式化为单独的行。下面是我目前正在使用的内容。

type Title = String
type Actor = String
type Cast = [Actor]
type Year = Int
type Fan = String
type Fans = [Fan]
type Period = (Year, Year)
type Film = (Title, Cast, Year, Fans)
type Database = [Film]

testDatabase :: Database
testDatabase = [("Casino Royale", ["Daniel Craig", "Eva Green", "Judi Dench"], 2006,          ["Garry", "Dave", "Zoe", "Kevin", "Emma"]),
("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”,它输出以下内容:

皇家赌场,丹尼尔克雷格,伊娃格林,朱迪丹奇,2006,5

牛仔与外星人,哈里森福特,丹尼尔克雷格,奥利维亚王尔德,2011 年,6

注意:格式很重要,每部电影都显示在单独的行和末尾的粉丝数量上的信息,而不是粉丝列表。

这是我解决这个问题的尝试-

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") 

但它似乎没有编译,但我似乎找不到我的代码有什么问题......是类型错误吗?

提前致谢!

4

1 回答 1

3

几个错误:

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
于 2013-04-20T14:16:01.833 回答