计算阵列的长度而不会炸毁堆栈

Roh*_*rma 0 f#

如何在不炸毁堆栈的情况下计算阵列的长度?我的两次尝试对我来说都不好看

let rec slowComputeLength xs = match xs with
                               | x::xss -> 1 + slowComputeLength xss
                               | _ -> 0

let computeLength xs = List.fold (fun acc _ -> acc + 1) 0 xs
Run Code Online (Sandbox Code Playgroud)

我可以想到在模式匹配的第一个版本中传递累加器,但这会使API变得丑陋

let rec slowComputeLength xs acc = match xs with
                                   | x::xss -> slowComputeLength xss acc+1
                                   | _ -> 0
Run Code Online (Sandbox Code Playgroud)

List.fold是正确的方式还是创建类似下面的东西,我相信它也会打到堆栈?

(1 + (1 + (1 + (...))))?
Run Code Online (Sandbox Code Playgroud)

PS - 我这样做是为了练习,理想情况下我们应该使用Array.Length.

Tom*_*cek 5

通常的技巧是定义一个嵌套的递归函数来保持累加器:

let computeLength xs = 
  let rec loop acc xs = 
    match xs with
    | _::xs -> loop (acc+1) xs
    | _ -> acc
  loop 0 xs
Run Code Online (Sandbox Code Playgroud)

这里,该loop函数具有附加的累加器参数,但它不会使外部computeLength函数的API 变得丑陋,因为该loop函数是嵌套的,并且永远不会被用户直接调用.

  • 它应该不是`| _ - > acc` (7认同)
  • @RohitSharma no,List.fold不会创建堆栈帧.它可以使用嵌套递归函数轻松实现,如本答案中所示.事实上,它似乎已经以这种方式实施; 请参阅https://github.com/fsharp/fsharp/blob/master/src/fsharp/FSharp.Core/list.fs#L237. (3认同)
  • 你有没有想到答案,它出现了?那不到一分钟. (2认同)