Recursive function vs recursive variable in F#

左心房为你撑大大i 提交于 2020-01-13 11:22:09

问题


The first method is OK. The second repeats constantly the same pair of numbers.

It is quite obscure to me why... Could you point to the good direction ?

module Normal = 
   let rnd = new MersenneTwister()
   let sampleNormal = 
      fun () -> let rec randomNormal() = let u1, u2 = rnd.NextDouble(),rnd.NextDouble()
                                         let r, theta= sqrt (-2. * (log u1)), 2. * System.Math.PI * u2  
                                         seq { yield r * sin theta; yield r * cos theta ; printfn "next";yield! randomNormal() }
                randomNormal()

   let sampleNormalBAD = 
      fun () -> let rec randomNormal = let u1, u2 = rnd.NextDouble(),rnd.NextDouble()
                                       let r, theta= sqrt (-2. * (log u1)), 2. * System.Math.PI * u2  
                                       seq { yield r * sin theta; yield r * cos theta ; printfn "next";yield! randomNormal }
                randomNormal

Normal.sampleNormal() |> Seq.take(10) |>Seq.toArray
Normal.sampleNormalBAD() |> Seq.take(10) |>Seq.toArray

回答1:


In the first sample randomNormal() is a function, it takes () and return a value, it will be evaluated each time. In the second one randomNormal is a value, so it will not be evaluated twice, once bounded it will remain with the same value.

If you rollover randomNormal() the signature is :

unit->seq<float>

and for randomNormal is just :

seq<float>

UPDATE: It keeps printing because the printfn is inside the sequence, which is the bounded value. If you try printing in the body before the last line you will see the difference. Here's a simplified sample code:

let sampleNormal = 
    fun () -> 
        let rec randomNormal() = 
            let u1, u2 = 1,2
            printfn "Evaluating"
            seq { yield u1; yield u2 ; printfn "next";yield! randomNormal() }
        randomNormal()

let sampleNormalBAD = 
    fun () -> 
        let rec randomNormal = 
            let u1, u2 = 1,2 
            printfn "Evaluating"
            seq { yield u1; yield u2 ; printfn "next";yield! randomNormal }
        randomNormal



回答2:


Completing Gustavo's answer, randomNormal is a value and after being computed by the interpreter, is bound to a sequence.

Further calls to randomNormal will yield this sequence, and the bindings used before the sequence have no reason to be evaluated. t, theta etc.. will always have the same value. What is inside the sequence will be evaluated though, hence the print.

In the case of randomNormal() the same happens, but the bindings are evaluated, as function might be relying on side effects.



来源:https://stackoverflow.com/questions/11285286/recursive-function-vs-recursive-variable-in-f

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!