简体   繁体   English

列表递归 - Haskell

[英]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! 谢谢!

Easy Fix 轻松修复

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

Better Versions 更好的版本

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: 这里有两个简单的想法:

List Comprehension 列表理解

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. 基本上,您根据第一个元素过滤列表,然后返回第二个元素。

Higher Order Functions 高阶函数

With higher order functions map , filter and fold , you can do as much as recursion and lcs, but often looks tidier. 使用更高阶函数mapfilterfold ,您可以执行递归和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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM