Haskell格式化和显示数据

时间:2013-04-20 13:58:22

标签: database haskell formatting

我正在努力展示信息并将它们格式化为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”的函数:

Casino Royale,Daniel Craig,Eva Green,Judi Dench,2006,5

牛仔& Aliens,Harrison Ford,Daniel Craig,Olivia Wilde,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") 

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

提前致谢!

1 个答案:

答案 0 :(得分: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]

这里我使用list comprehension来制作一个带有分隔符的字符串列表,然后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和第二个,{ {1}}很方便:

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"