输出自定义数据类型列表的内容

时间:2014-02-24 15:53:22

标签: haskell

我有一个自定义数据类型Movie = String Int [(String,Int)](电影名称年份[(粉丝,评分)],并希望做一些事情:

首先,我想创建一个函数,从元组列表中平均Ints,并输出该数字。到目前为止,我有这个不完整的功能:

avgRating :: [DataType] -> Int avgRating [(Movie a b [(fan,rating)])] = sumRatings / (length [<mylist>])

这里我需要一个函数sumRatings来递归列表并总结所有评级,但我不知道从哪里开始。

我在这里遇到的另一个问题是,我不确定将<mylist>放在哪里,因为我通常会给列表一个变量名,然后在那里使用它,但是因为我将列表拆分了定义其他变量我无法命名。

我希望这是有道理的,谢谢。

2 个答案:

答案 0 :(得分:4)

我猜你有一个定义为

的数据结构
data Movie = Movie String Int [(String, Int)]

虽然这有效,但是当你拥有那么多字段时,使用它可能有点麻烦。相反,您可以利用类型别名并将语法记录为

type Name = String
type Year = Int
type Rating = Int

data Movie = Movie
    { mName :: Name
    , mYear :: Year
    , mRatings :: [(Name, Rating)]
    } deriving (Eq, Show)

现在事情变得更加明确,更容易使用。 mNamemYearmRatings函数将使用Movie并从中返回相应的字段。您的Movie构造函数仍然以相同的方式工作,因此它不会破坏现有代码。

要计算评分的平均值,您真的需要一个能够提取电影所有评分的功能,并将它们汇总到一个列表中:

ratings :: Movie -> [Rating]
ratings mov = map snd $ mRatings mov

然后你只需要一个average功能。这将有点不同,因为您无法直接计算Int的平均值,您必须转换为浮点类型:

average :: [Rating] -> Float   -- Double precision isn't really needed here
average rs = fromIntegral (sum rs) / fromIntegral (length rs)

fromIntegral函数将Int转换为Float(实际的类型签名更为通用)。由于sum的{​​{1}}是Int且列表的Int始终为length,因此您需要转换这两者。

现在你可以把它们组成一个函数:

Int

现在,如果您需要计算多部电影的平均评分,可以将movieAvgRating :: Movie -> Float movieAvgRating = average . ratings 应用于每部电影,将其汇总到一个评分列表中,然后在其上调用ratings。我建议查看average函数。你会想要制作像

这样的功能
concatMap

答案 1 :(得分:1)

要先回答第二个问题,您可以使用@绑定到变量并同时将其解压缩:

avgRating [(Movie a b mylist@[(fan, rating)])] = …

另请注意,如果您不打算使用解包的变量,那么将Haskell约定绑定到_

avgRating [(Movie _ _ mylist@[(fan, rating)])] = …

这有助于读者关注真正重要的事情。

我不想只为您提供递归问题的解决方案,因为学习编写递归函数是Haskell编程的一个重要且有益的部分。 (如果你真的希望我为你破坏它,请在评论中告诉我。)然而,基本的想法是你需要考虑两种不同的情况:基本情况(递归停止的地方)和递归情况。例如,考虑内置的sum函数:

sum :: Num a => [a] -> a
sum [] = 0
sum (x:xs) = x + sum xs

这里,基本情况是sum得到一个空列表 - 它只是求值为0.在递归的情况下,我们假设sum已经可以产生一个较小列表的总和,并且我们将其扩展到更大的列表。

如果你在一般的递归方面遇到麻烦,Harold Abelson和Gerald Jay Sussman将在Structure and Interpretation of Computer Programs,第二版,麻省理工学院出版社(剑桥),1996年开始详细讨论这个主题。 。 21(§§1.1.7–1.2)。它在Scheme中,而不是Haskell,但语言非常相似 - 至少在这个概念层面 - 每个语言都可以作为另一个的合适模型。