列表递归-Haskell

时间:2019-02-27 17:24:28

标签: list haskell recursion tuples

基本上,我有这个练习:回顾上周的StudentMark类型同义词。编写一个递归函数:

0{"sid":"UeC7GEdBUWNM2Wm9AAAF","upgrades":[],"pingInterval":25000,"pingTimeout":5000}

给出特定学生的分数列表;例如:

listMarks :: String -> [StudentMark] -> [Int]

这是我编写函数的方式:

listMarks "Joe" [("Joe", 45), ("Sam", 70), ("Joe", 52)] = [45,52]

如果列表中的字符串与“ std”字符串不同,则此方法不起作用。我想了解为什么以及如何进行这项工作?谢谢!

1 个答案:

答案 0 :(得分:7)

轻松修复

只需更改防护装置| otherwise = listMarks std xs。我还要在上面的防护措施中进行更改,因为| std == fst x = snd x : listMarks std xs是的,它们是相等的,但是它使您更清楚地实现了什么。因此您的代码应为:

type StudentMark = (String, Int)
listMarks :: String -> [StudentMark] -> [Int]
listMarks _ [] = []
listMarks std (x:xs)
  | std == fst x = snd x : listMarks std xs
  | otherwise = listMarks std xs

更好的版本

如您所见,您将使用始终相同的第一个参数来调用该函数,因此很有可能可以编写更整洁的版本。这里有两个简单的想法:

列表理解

我个人最喜欢的列表理解非常明确和明确:

listMarks' :: String -> [StudentMark] -> [Int]
listMarks' str marks = [m |(n,m) <- marks, n==str]

基本上,您会根据第一个元素过滤列表,然后返回第二个元素。

高阶函数

使用高阶函数mapfilterfold,您可以完成递归和lcs的工作,但看起来却比较整齐。同样,您想基于第一个元素过滤列表,然后返回第二个。

listMarks'' :: String -> [StudentMark] -> [Int]
listMarks'' str =  map snd . filter (\(n,_) -> n == str)