首页 > 解决方案 > 如何在 F# 中递归调用

问题描述

我正在将 ac# 递归函数转换为 f#。我对 F# 不是很熟悉。我有一堆错误,我不知道为什么。我确实查找了递归函数语法,但是对于我拥有的所有 if 语句,我对如何在 f# 中编写它感到困惑。

这是c#递归函数

    private List<double> ReturnClosestInList(List<double> allKey, int begin, int end)
    {
        if (end >= begin)
        {
            int mid = begin + (end - begin) / 2;
            if (allKey[mid] > input) return ReturnClosestInList(allKey, begin, mid - 1);
            return ReturnClosestInList(allKey, mid + 1, end);
        }
        if (end < 0) end = begin + 1;
        if (begin < 0) begin = end + 1;
        if (end > allKey.Count - 1) end = begin - 1;
        if (begin > allKey.Count - 1) begin = end - 1;
        return new List<double> { allKey[begin], allKey[end] };
    }

这是我编写的 f# 代码和错误

let rec ReturnClosestInList (allKey : List<double>) (start : int) (finish : int) (input : double)= 
    if(finish >= start) then
        let mid = start + (finish - start) / 2
        if(allKey.[mid] > input) then
            ReturnClosestInList allKey start (mid - 1) input
        else ReturnClosestInList allKey (start + 1) mid input

    else
        if finish < 0 then 
            finish = start + 1
        elif start < 0 then
            start = finish + 1
        elif finish > allKey.Length - 1 then
            finish = start - 1
        else start > allKey.Length - 1 then
            start = finish - 1

    let c : List<double> = [allKey.[start]; allKey.[finish]]
    c

标签: c#f#

解决方案


您的代码有两个问题。首先是您将startandfinish视为可变值。另一个是您的else分支不返回值。

要解决前者,我认为最好的方法是使用以下方法重新分配变量:

let start, finish = 
    if finish < 0 then 
        start, start + 1
    elif start < 0 then
        finish + 1, finish
    elif finish > allKey.Length - 1 then
        start, start - 1
    elif start > allKey.Length - 1 then
        finish - 1, finish
    else start, finish

这个想法是您正在定义同名的新变量,并为它们分配一个新值。由于您需要更新其中一个或另一个的值,因此代码会重新分配它们(else分支没有做任何特别的事情)。

第一个问题是你的两个分支if都必须返回一个结果。为此,您需要编写如下内容:

if(finish >= start) then
    let mid = start + (finish - start) / 2
    if(allKey.[mid] > input) then
        ReturnClosestInList allKey start (mid - 1) input
    else ReturnClosestInList allKey (start + 1) mid input
else
    let start, finish = 
        // (all the code to tweak start/finish goes here)
    [allKey.[start]; allKey.[finish]]

这样,ifcase 的返回值就是你从递归调用中得到的任何值。另一种情况的回报是您使用[ ... ].

还值得注意的是,您的代码看起来不是很实用,因此如果您正在学习 F#,我建议您使用模式匹配而不是从 C# 转换代码来编写此代码。你会得到一个更好、更容易理解的解决方案。


推荐阅读