这两个定义是相同还是不同

时间:2018-07-25 23:14:03

标签: recursion f#

查看以下定义:

let rec extractOdds list = ​
  match list with ​
  | [] -> []​
  | x::xs -> ​
      if x%2=0 then extractOdds xs else x::extractOdds xs​

let rec extractOdds list = ​
  match list with ​
  | [] -> []​
  | x::xs -> ​
      let rest = extractOdds xs​
      if x%2=0 then rest else x::rest​

我想知道两者是否相同。由于第一个定义立即使用了递归调用。而第二个则创建与extractOdds xs的let绑定,并在if表达式中使用它。

如果两者的实现方式相同或不同,请指导我。

1 个答案:

答案 0 :(得分:1)

两者之间的差别很小,实际上没有作用:

  • 第一个版本在评估x%2=0之前先评估条件extractOdds xs
  • 第二个版本在评估条件extractOdds xs之前先调用x%2=0

顺序将保留在编译后的代码中(对于第一个版本可能会更长一些),因此两个版本略有不同,但是无论如何都无法观察到-两个调用都没有任何副作用-效果和对extractOdds xs的调用,无论x%2=0true还是false都是如此。

如果您也使用let绑定重写第一个版本,这可能会更明显:

let rec extractOdds list = ​
  match list with ​
  | [] -> []​
  | x::xs -> ​
      if x%2=0 then 
        let rest = extractOdds xs 
        rest 
      else 
        let rest = extractOdds xs​
        x::rest

现在您可以清楚地看到条件和let绑定的顺序是与以下内容的唯一区别:

let rec extractOdds list = ​
  match list with ​
  | [] -> []​
  | x::xs -> ​
      let rest = extractOdds xs​
      if x%2=0 then 
        rest 
      else 
        x::rest

编辑:可以使用“累加器”参数编写尾部递归版本。这样,您将以错误的顺序收集元素,因此您需要在返回结果列表之前对其进行反转:

let rec extractOdds acc list = ​
  match list with ​
  | [] -> List.rev acc
  | x::xs -> ​
      extractOdds (if x%2=0 then acc else x::acc) xs​