Haskell 输出自定义数据类型列表的内容
我有一个自定义数据类型Haskell 输出自定义数据类型列表的内容,haskell,Haskell,我有一个自定义数据类型Movie=String Int[(String,Int)](电影名称年份[(粉丝,评级)],我想做几件事: 首先,我想做一个函数,对元组列表中的整数求平均值,然后只输出那个数。到目前为止,我有一个不完整的函数: sum :: Num a => [a] -> a sum [] = 0 sum (x:xs) = x + sum xs movieAvgRating :: Movie -> Float movieAvgRating = average . ra
Movie=String Int[(String,Int)]
(电影名称年份[(粉丝,评级)],我想做几件事:
首先,我想做一个函数,对元组列表中的整数求平均值,然后只输出那个数。到目前为止,我有一个不完整的函数:
sum :: Num a => [a] -> a
sum [] = 0
sum (x:xs) = x + sum xs
movieAvgRating :: Movie -> Float
movieAvgRating = average . ratings
avgRating::[DataType]->Int
avgRating[(电影a b[(影迷、评级)]]=sumRatings/(长度[])
在这里,我需要一个函数sumRatings在列表中递归并对所有评级求和,但我不确定从哪里开始
我在这里遇到的另一个问题是,我不确定将什么放在
的位置,因为我通常会给列表一个变量名,然后在那里使用它,但由于我已经将列表拆分以定义其他变量,所以我无法命名它
我希望这是有意义的,谢谢。要先回答第二个问题,您可以绑定到一个变量,并使用
@
同时解压它:
avgRating [(Movie a b mylist@[(fan, rating)])] = …
还要注意的是,如果您不打算使用解包的变量,则Haskell约定将它们绑定到\uuu
:
avgRating [(Movie _ _ mylist@[(fan, rating)])] = …
这有助于读者关注真正重要的东西
我不想只是给你递归问题的解决方案,因为学习编写递归函数是Haskell编程中一个重要且有益的部分。(如果你真的想让我破坏它,请让我在评论中告诉你。)然而,基本思想是你需要考虑两种不同的情况:基本情况(递归停止)和递归情况。作为例子,考虑内置的<代码>和<代码>函数:
sum :: Num a => [a] -> a
sum [] = 0
sum (x:xs) = x + sum xs
movieAvgRating :: Movie -> Float
movieAvgRating = average . ratings
这里,基本情况是当sum
得到一个空列表时–它的计算结果仅为0。在递归情况下,我们假设sum
已经可以生成一个较小列表的和,并扩展它以覆盖一个较大的列表
如果你在递归方面遇到了问题,Harold Abelson和Gerald Jay Sussman在麻省理工学院出版社(剑桥)1996年第2版中详细讨论了这个问题,从第21页开始()。这是Scheme,不是Haskell,但这两种语言非常相似——至少在这个概念层面上如此——因此每种语言都可以作为另一种语言的一个像样的模型。首先回答第二个问题,您可以绑定到一个变量,然后使用
@
同时解包:
avgRating [(Movie a b mylist@[(fan, rating)])] = …
还要注意的是,如果您不打算使用解包的变量,则Haskell约定将它们绑定到\uuu
:
avgRating [(Movie _ _ mylist@[(fan, rating)])] = …
这有助于读者关注真正重要的东西
我不想只是给你递归问题的解决方案,因为学习编写递归函数是Haskell编程中一个重要且有益的部分。(如果你真的想让我破坏它,请让我在评论中告诉你。)然而,基本思想是你需要考虑两种不同的情况:基本情况(递归停止)和递归情况。作为例子,考虑内置的<代码>和<代码>函数:
sum :: Num a => [a] -> a
sum [] = 0
sum (x:xs) = x + sum xs
movieAvgRating :: Movie -> Float
movieAvgRating = average . ratings
这里,基本情况是当sum
得到一个空列表时–它的计算结果仅为0。在递归情况下,我们假设sum
已经可以生成一个较小列表的和,并扩展它以覆盖一个较大的列表
如果你在递归方面遇到了问题,Harold Abelson和Gerald Jay Sussman在麻省理工学院出版社(剑桥)1996年第2版中详细讨论了这个问题,从第21页开始().这是Scheme,不是Haskell,但两种语言非常相似——至少在这个概念层面上是如此——以至于每一种语言都可以作为另一种语言的合适模型。我猜您的数据结构定义为
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
和mRatings
函数将获取一个Movie
并从中返回相应的字段。您的Movie
构造函数仍然以同样的方式工作,因此它不会破坏现有代码
要计算收视率的平均值,您确实需要一个函数来提取电影的所有收视率并将其聚合到列表中:
ratings :: Movie -> [Rating]
ratings mov = map snd $ mRatings mov
然后您只需要一个average
函数。这将有点不同,因为您无法直接计算Int
s的平均值,您必须转换为浮点类型:
average :: [Rating] -> Float -- Double precision isn't really needed here
average rs = fromIntegral (sum rs) / fromIntegral (length rs)
fromIntegral
函数将Int
转换为Float
(实际的类型签名更一般一些)。由于Int
s的和都是Int
,列表的长度始终是Int
,因此需要将两者转换
现在,您可以将它们组合成一个函数:
sum :: Num a => [a] -> a
sum [] = 0
sum (x:xs) = x + sum xs
movieAvgRating :: Movie -> Float
movieAvgRating = average . ratings
现在,如果你需要计算几部电影的平均收视率,你可以对每部电影应用收视率
,将它们聚合到一个收视率列表中,然后调用平均值
。我建议你看看concatMap
函数。你会想要做一个类似这样的函数
moviesAvgRating :: [Movie] -> Float
moviesAvgRating movs = average $ ???
我猜您的数据结构定义为
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
和mRatings
函数将获取一个Movie
并从中返回相应的字段。您的Movie
构造函数仍然以同样的方式工作,因此它不会破坏现有代码
要计算收视率的平均值,您确实需要一个函数来提取一部电影的所有收视率,并将其聚合到