首页 > 解决方案 > 如何在所有情况下使这个 F# 函数尾递归?

问题描述

我一直在努力解决今年的 F# 代码出现问题,以此来提高我在这门语言方面的技能。我为第 8 天第 1 部分提出了以下解决方案:

namespace AdventOfCode2018.Core

module Day8 =

    let calculatePart1 input = 
        let rec take numberToTake numberTaken taken remaining =
            if numberTaken = numberToTake || List.isEmpty remaining then
                taken, remaining
            else
                take numberToTake (numberTaken + 1) 
                    (List.head remaining :: taken) (List.tail remaining)

        let rec calculate input sum depth maxDepth =
            let quantityOfChildNodes, quantityOfMetadata, remaining = 
                match input with
                | qc :: qm :: tl -> qc, qm, tl
                | _ -> 0, 0, []
            let input, sum = 
                match quantityOfChildNodes with 
                | 0 -> remaining, sum
                | q -> calculate remaining sum 1 q
            let metadata, remaining = take quantityOfMetadata 0 [] input
            let sum = sum + List.sum metadata
            if depth = maxDepth then remaining, sum
            else calculate remaining sum (depth + 1) maxDepth

        calculate input 0 0 1 |> snd

我的代码对问题产生了正确的解决方案,并且似乎运行得足够快(在 i7 机器上使用我的拼图输入 13 毫秒)。但是,在调试代码时,我注意到它不是尾递归的。其中的第一个递归调用会calculate生成一个新的堆栈帧。函数末尾的第二个递归调用没有。我确信必须可以将第一个调用编写为尾递归,但我不确定如何。

标签: recursionf#

解决方案


推荐阅读