当以函数式风格编写代码时,您通常会使用递归,如果不是显式的,然后是隐式的,因为大多数列表/数组/序列函数都在底层使用递归。
在 F# 中,您需要明确声明函数是递归的,因此您创建的函数将在其定义中使用 let rec 语法。根据您的要求,您的函数可能如下所示:
let rec myFilter (name: string) (input: (string * string * int) list) =
...
对于这类递归迭代列表的问题,您通常使用模式匹配来检查您是否在列表末尾,如果是,则返回一个空列表。
let rec myFilter (name: string) (input: (string * string * int) list) =
match input with
| [] -> []
...
现在您需要编写一个模式匹配来检查元组中的第一项与提供的名称是否相符。可以在列表头部使用模式匹配,F#的when语法解构列表头部进行比较
let rec myFilter (name: string) (input: (string * string * int) list) =
match input with
| [] -> []
| ((a, b, _) :: rest) when a = name -> b :: myFilter name rest
...
当a 与查询的名称匹配时,第二种情况匹配。当它匹配时,它将返回一个新列表,其中b 是列表的头部,然后它将获取元组列表的其余部分并递归调用myFilter。这就是递归遍历列表的方式。
我们还有一个案例要检查:如果我们没有找到匹配项,我们希望继续遍历列表而不收集 b。这可以通过剥离头部并递归调用myFilter 来表达,只发送其余的元组。
let rec myFilter (name: string) (input: (string * string * int) list) =
match input with
| [] -> []
| ((a, b, _) :: rest) when a = name -> b :: myFilter name rest
| (_ :: rest) -> myFilter name rest
调用myFilter "a" [("a","x",3);("b","y",4);("a","z",5)] 然后产生["x"; "z"],正如预期的那样。