【问题标题】:Recursive function vs recursive variable in F#F#中的递归函数与递归变量
【发布时间】:2012-07-01 20:11:03
【问题描述】:

第一种方法没问题。 第二个不断重复同一对数字。

这对我来说很模糊,为什么...你能指出好的方向吗?

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

【问题讨论】:

  • 我猜它与不变性有关。

标签: recursion f#


【解决方案1】:

在第一个示例中randomNormal() 是一个函数,它接受() 并返回一个值,每次都会对其进行评估。 在第二个中,randomNormal 是一个值,因此它不会被计算两次,一旦有界它将保持相同的值。

如果你翻转randomNormal(),签名是:

unit->seq<float>

randomNormal 只是:

seq<float>

更新:它继续打印,因为printfn 在序列内,这是有界值。 如果您尝试在最后一行之前的正文中打印,您会看到不同之处。这是一个简化的示例代码:

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

【讨论】:

  • 这是有道理的,但不知何故,两者都“运行”打印,所以我预计 rnd.NextDouble() 也会被重新评估。可能是#nowarn 40 最终有意义(原文如此)。
  • 所以关键在于你所说的绑定概念
  • 是的,这就是为什么它将始终保持相同的值。
  • 是的,它一直在打印。它似乎同时捕捉到了价值和副作用。非常有趣的 +1。
  • 我会仔细阅读绑定机制,以确定它的确切作用。
【解决方案2】:

完成 Gustavo 的回答,randomNormal 是一个值,在被解释器计算后,绑定到一个序列。

randomNormal 的进一步调用将产生这个序列,并且在序列之前使用的绑定没有理由被评估。 t、theta 等.. 将始终具有相同的值。 序列内部将被评估,因此打印。

randomNormal() 的情况下也会发生同样的情况,但会评估绑定,因为函数可能依赖于副作用。

【讨论】:

    猜你喜欢
    • 2010-12-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-11
    • 1970-01-01
    • 2011-03-15
    • 2021-12-11
    相关资源
    最近更新 更多