F#递归行为

Mr.*_*din 3 recursion f#

我最近开始学习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
Run Code Online (Sandbox Code Playgroud)

现在,当你运行它时,你会发现这最终会返回一个大于20的数字.

当您查看输出时,您会发现它没有打印出最后一个数字列表,我无法弄清楚原因.

Pat*_*iek 9

序列被懒惰地评估并且不被高速缓存.这里发生的是你有一个副作用的序列被多次评估.

第一次评估产生第一个随机数序列:

numbers |> Seq.iter( fun n -> printf "%i " n )
Run Code Online (Sandbox Code Playgroud)

第二个调用再次运行评估,产生完全不同的序列:

let total = numbers |> Seq.sum
Run Code Online (Sandbox Code Playgroud)

如果要保持第一次评估以多次运行它,您需要做的是实现序列或缓存它:

// 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
Run Code Online (Sandbox Code Playgroud)