我猜你的数据结构定义为
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)
现在事情变得更加明确并且更容易使用。这mName
, mYear
, and mRatings
函数将需要一个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)
The fromIntegral
函数转换一个Int
to a Float
(实际的类型签名更通用一些)。由于两者sum
of Int
s is an Int
和length
列表的永远是一个Int
,您需要将两者都转换。
现在您可以将它们组合成一个函数:
movieAvgRating :: Movie -> Float
movieAvgRating = average . ratings
现在,如果您需要计算几部电影的平均评分,您可以应用ratings
对于每个人,将它们汇总到一个评级列表中,然后调用average
关于这一点。我建议看看concatMap
功能。你会想要创建一个像这样的函数
moviesAvgRating :: [Movie] -> Float
moviesAvgRating movs = average $ ???