F#递归行为

3

最近我开始学习F#,因为对于大部分函数式编程概念我都比较陌生,所以我倾向于为自己编写小例子并通过测试结果来检查我的前提条件。

现在我似乎无法理解以下代码的结果以及其为什么会呈现出这样的行为。用例:我掷四个六面骰子,只有当它们的总和大于20时才返回它们的总和。

这是我的代码:

let rnd = System.Random()
let d6 () = rnd.Next(1, 7)
let rec foo () =
    // create a list of 4 d6 throws and print out the list
    let numbers = seq { for i in 1 .. 4 -> d6() }
    numbers |> Seq.iter( fun n -> printf "%i " n )
    printfn "\n"

    // sum the list and return the sum only when the sum is greater than 20
    let total = numbers |> Seq.sum
    match total with
    | n when n < 21 -> foo ()
    | _ -> total

现在当你运行它时,你会发现它最终会返回一个大于20的数字。 当你查看输出时,你会发现它没有打印出最后一组数字,我无法弄清楚为什么。
1个回答

9

这些序列是惰性求值的,不会被缓存。这里发生的是你有一个带有副作用的序列,它会被多次求值。

第一次求值会产生第一个随机数序列:

numbers |> Seq.iter( fun n -> printf "%i " n )

第二次调用会再次运行评估,生成完全不同的序列:
let total = numbers |> Seq.sum

如果您想多次运行第一次评估,需要做的是将序列实体化或缓存它:

// create a list directly
let numbers = [ for i in 1 .. 4 -> d6() ] 
// or create a list from sequence
let numbers = seq { for i in 1 .. 4 -> d6() } |> List.ofSeq
// or cache the sequence
let numbers = seq { for i in 1 .. 4 -> d6() } |> Seq.cache

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接