Recursion F#用实际值替换变量会导致无限循环(递归函数)

Recursion F#用实际值替换变量会导致无限循环(递归函数),recursion,f#,infinite-loop,Recursion,F#,Infinite Loop,我最近从F#开始,实现了一个非常基本的递归函数,它代表了Eratosthenes筛。我提出了以下工作代码: static member internal SieveOfEratosthenesRecursive sequence accumulator = match sequence with | [] -> accumulator | head::tail -> let rest = tail |> List.filter(fun number -&

我最近从F#开始,实现了一个非常基本的递归函数,它代表了Eratosthenes筛。我提出了以下工作代码:

static member internal SieveOfEratosthenesRecursive sequence accumulator =
    match sequence with
    | [] -> accumulator
    | head::tail -> let rest = tail |> List.filter(fun number -> number % head <> 0L)
                    let newAccumulator = head::accumulator
                    Prime.SieveOfEratosthenesRecursive rest newAccumulator
静态成员内部SieveFeratosines递归序列累加器=
匹配序列
|[]->累加器
|head::tail->let rest=tail |>List.filter(有趣的数字->数字%head 0L)
让newacculator=head::acculator
Prime.sieveoferatostenes递归剩余新累加器
这个函数并没有真正的内存效率,所以我试图消除变量“rest”和“newacculator”。我想出了以下代码

static member internal SieveOfEratosthenesRecursive sequence accumulator =
    match sequence with
    | [] -> accumulator
    | head::tail -> tail    |> List.filter(fun number -> number % head <> 0L) 
                            |> Prime.SieveOfEratosthenesRecursive (head::accumulator)
静态成员内部SieveFeratosines递归序列累加器=
匹配序列
|[]->累加器
|head::tail->tail |>List.filter(有趣的数字->数字%head 0L)
|>Prime.sieveoferatostenesrecursive(头::累加器)
据我所知,我读过的教程Prime.sieveoferatosonesrecursive将被调用,过滤后的tail作为第一个参数,由head::acculator组成的列表作为第二个参数。然而,当我试图以较少的变量使用量运行代码时,程序会陷入无限循环。为什么会发生这种情况?我做错了什么

据我所知,我读过的教程Prime.siveoferatosNesRecursive将被调用,第一个参数是过滤后的
tail
,第二个参数是由
head::acculator
组成的列表

你把这个倒过来

在第一个版本中,您要传递
rest
然后
newacculator
;在第二个版本中,您实际上是在传递
newacculator
然后
rest
。也就是说,你已经转换了论点

Prime.sieveoferatosonesrecursive(head::accumulator)
是一个部分函数应用程序,其中应用
(head::accumulator)
作为第一个参数(
序列
)。此分部函数应用程序将生成一个一元函数(应为
累加器
),您将(通过
|>
)传递到该函数,在代码的第一个版本中称之为
rest

改变<代码> sieEfErrastOth.Stutials//Cord>的参数顺序是最简单的解决方案,但我也会考虑如下类似的习惯用法:

static member internal SieveOfEratosthenesRecursive sequence accumulator =
    match sequence with
    | [] -> accumulator
    | head::tail ->
        tail
        |> List.filter(fun number -> number % head <> 0L) 
        |> Prime.SieveOfEratosthenesRecursive <| (head::accumulator)
静态成员内部SieveFeratosines递归序列累加器=
匹配序列
|[]->累加器
|头:尾->
尾
|>列表.过滤器(乐趣编号->编号%head 0L)
|>Prime.sieveoferatostenes递归累加器
|头:尾->
尾
|>列表.过滤器(乐趣编号->编号%head 0L)
|>flipzip(头部:累加器)
||>Prime.sieveoferatos递归


FWIW,将
rest
newacculator
作为命名变量删除,不会对内存使用产生丝毫影响。

第二个函数中的最后一个调用相当于:

Prime.SieveOfEratosthenesRecursive newAccumulator rest
在这里,您可以切换两个参数的位置。由于
newacculator
在每次递归调用后都会变大,因此您永远不会达到空列表的基本情况

经验法则是最后放置最常更改的参数:

let rec sieve acc xs =
    match xs with
    | [] -> acc
    | x::xs' -> xs' |> List.filter (fun y -> y % x <> 0L) 
                    |> sieve (x::acc)

使用pipe(
|>
)操作符只会使函数更具可读性,根本不会影响内存使用。

你说得对。谢谢你指出这一点。管道参数将作为最后一个参数传入
let rec sieve acc xs =
    match xs with
    | [] -> acc
    | x::xs' -> xs' |> List.filter (fun y -> y % x <> 0L) 
                    |> sieve (x::acc)
let rec sieve acc = function
    | [] -> acc
    | x::xs' -> xs' |> List.filter (fun y -> y % x <> 0L) 
                    |> sieve (x::acc)