[英]Recursion over Lists - Haskell
Basically I have this exercise: Recall the StudentMark type synonym from last week. 基本上我有这个练习:回忆一下上周的StudentMark类型同义词。 Write a recursive function: 写一个递归函数:
listMarks :: String -> [StudentMark] -> [Int]
which gives a list of the marks for a particular student; 它给出了特定学生的分数列表; for example: 例如:
listMarks "Joe" [("Joe", 45), ("Sam", 70), ("Joe", 52)] = [45,52]
This was the way I wrote the function: 这就是我编写函数的方式:
type StudentMark = (String, Int)
listMarks :: String -> [StudentMark] -> [Int]
listMarks _ [] = []
listMarks std (x:xs)
| std == fst x = snd x : listMarks (fst x) xs
| otherwise = listMarks (fst x) xs
This does not work if a string from the list is different from the "std" string. 如果列表中的字符串与“std”字符串不同,则不起作用。 I would like to understand why and how could I make this work? 我想了解为什么以及如何才能完成这项工作? Thank you! 谢谢!
Just change the guard | otherwise = listMarks std xs
只需改变守卫| otherwise = listMarks std xs
| otherwise = listMarks std xs
. | otherwise = listMarks std xs
。 I would also change it in the guard above, as | std == fst x = snd x : listMarks std xs
我也会在上面的警卫中改变它,因为| std == fst x = snd x : listMarks std xs
| std == fst x = snd x : listMarks std xs
as yes, they are equal, but it makes it more clear what you want to achieve. | std == fst x = snd x : listMarks std xs
as yes,它们是相同的,但它更清楚你想要实现的目标。 so your code would be: 所以你的代码将是:
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
As you can see, you ae calling the function with always the same first argument, so it's highly likely you can write a neater version. 正如您所看到的,您使用始终相同的第一个参数调用该函数,因此您很可能编写一个更整洁的版本。 Here are two quick ideas: 这里有两个简单的想法:
Personally my favourite, list comprehensions are very versitile and clear: 就我个人而言,列表理解是非常多才多艺和清晰的:
listMarks' :: String -> [StudentMark] -> [Int]
listMarks' str marks = [m |(n,m) <- marks, n==str]
Basically you filter the list based on the first element, and then you return the second one. 基本上,您根据第一个元素过滤列表,然后返回第二个元素。
With higher order functions map
, filter
and fold
, you can do as much as recursion and lcs, but often looks tidier. 使用更高阶函数map
, filter
和fold
,您可以执行递归和lcs,但通常看起来更整洁。 You want to, again, filter the list based on the first element, and then you return the second one. 您希望再次根据第一个元素过滤列表,然后返回第二个元素。
listMarks'' :: String -> [StudentMark] -> [Int]
listMarks'' str = map snd . filter (\(n,_) -> n == str)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.