Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/fsharp/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
F# 为什么不是';这个函数不是递归的吗?_F#_Tail Recursion - Fatal编程技术网

F# 为什么不是';这个函数不是递归的吗?

F# 为什么不是';这个函数不是递归的吗?,f#,tail-recursion,F#,Tail Recursion,我编写了一个基本的Eratosthenes的筛选函数,最初以head::(innerSieve tail)结尾,我注意到它不是递归的 然后我对它进行了如下修改,以使用累加器。此代码现在应该是尾部递归的: let Sieve n = let rec innerSieve primes numbers = match numbers with | [] -> primes | h :: t -> innerSi

我编写了一个基本的Eratosthenes的筛选函数,最初以
head::(innerSieve tail)
结尾,我注意到它不是递归的

然后我对它进行了如下修改,以使用累加器。此代码现在应该是尾部递归的:

let Sieve n =     

    let rec innerSieve primes numbers =     
        match numbers with
        | [] -> primes
        | h :: t -> innerSieve (h :: primes) (List.filter (fun x -> x % h > 0) t) 

    innerSieve [] [2 .. n] |> List.rev

printf "%A" (Sieve 10000)
但是,即使在释放模式下,此功能的内存使用量也会以
n
的大小(每+1000+1-2MB)快速增长。我错过什么了吗

编辑:以n=100M的速度运行的VS屏幕截图:


回答您的问题:函数是尾部递归的-但这并不意味着它具有神奇的内存效率


真正的问题是
列表
在内存中的处理/保存方式(它们变得非常大、非常快)

这就是列表的问题:如果列表太大(开销太大……),它们就不是真正的最优,所以通常的第一步是使用数组

是的,它在这里工作得很好(memroy wise):


当然,这也会运行很长时间……但在我的机器上,内存消耗是TCO,这只意味着调用堆栈不会弹出。为什么您认为内存使用与尾部调用有关?您使用过探查器吗?是的(请参阅问题补充以获取屏幕截图)。当n=100M时,内存使用量很快超过2GB,并在不久后出现OutOfMemoryException。快照功能无法终止,但它可以检测数百万个对象。如果我理解正确,使用TCO,内存中最多应该有一个数字列表?那么,仅100.000.000 Int32值就约380MB(仅来自您的[2..n])-现在添加您正在生成的所有中间列表…似乎是在添加…不-这只是意味着您没有为堆栈上的函数调用分配内容谢谢!我对
List
Array
之间的巨大差异感到非常震惊;我认为整数的链接列表在最坏的情况下是2-3倍大作为等效数组,由于指针的成本。一定要记住。
let inline divides d n = n % d > 0

let rec innerSieve primes numbers =     
    if Array.isEmpty numbers
    then primes
    else 
        let h = numbers.[0]
        let numbers' = numbers |> Array.filter (divides h)
        in innerSieve (h :: primes) numbers'

let Sieve n =     
    innerSieve [] [| 2 .. n |] |> List.rev