F#-在排序列表中插入元素尾递归

问题描述

我正在尝试在F#中将以下普通递归代码转换为尾递归,但我失败了。

let rec insert elem lst = 
    match lst with
    | [] -> [elem]
    | hd::tl -> if hd > elem then 
                    elem::lst
                else 
                    hd::(insert elem tl) 

let lst1 = []

let lst2 = [1;2;3;5]

printfn "\nInserting 4 in an empty list:  %A" (insert 4 lst1)
printfn "\nInserting 4 in a sorted list:  %A" (insert 4 lst2)

你们能帮忙吗?不幸的是我是f#的初学者。另外,有人可以给我指出一个好的教程来理解尾递归吗?

解决方法

尾部递归的点如下:从函数返回之前的最后一个操作是对自身的调用;这称为 tail调用,并且是 tail recursion 的名称来源(递归调用位于最后,即尾部位置)。

您的函数不是尾部递归的,因为它的至少一个分支在递归调用之后(list cons运算符)有一个操作。

将递归函数转换为尾递归函数的通常方法是添加一个参数以累加中间结果( accumulator )。当涉及到列表时,并且当您意识到唯一的基本列表操作在元素之前时,这还意味着在处理完列表之后,该列表将被反转,因此通常必须反转生成的累加器再次。

考虑到所有这些要点,并且鉴于我们不想通过添加从调用者的角度来看多余的参数来更改函数的公共接口,我们将实际工作移至内部子函数。这个特定的函数稍微复杂些,因为在插入元素之后,除了重新连接两个部分列表,别无他法,其中一个现在是相反的顺序,而另一个则不是。我们创建了第二个内部函数来处理该部分,因此整个函数如下所示:

let insert elm lst =
    let rec iter acc = function
        | [] -> List.rev (elm :: acc)
        | (h :: t) as ls ->
            if h > elm then finish (elm :: ls) acc
            else iter (h :: acc) t
    and finish acc = function
        | [] -> acc
        | h :: t -> finish (h :: acc) t
    iter [] lst

为了进一步研究,Scott Wlaschin的 F#for Fun and Profit 是一个很好的资源,并且尾递归在有关递归类型及更多内容的较大章节中进行了介绍:https://fsharpforfunandprofit.com/posts/recursive-types-and-folds

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...