F # recursive behavior

I recently started learning F # and because I'm completely new to most functional concepts, I tend to write small examples for myself and check my premises with test results.

Now I cannot understand the result of the following code and why it behaves as such. Use case: I flip four dice with six sides and only return them when their total is greater than 20.

This is my code:

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

      

Now when you run this, you will find that it will eventually return a number greater than 20.

When you look at the output, you will find that it did not print out the last list of numbers, and I cannot figure out why.

+3


source to share


1 answer


Sequences are lazily evaluated and not cached. What's happening here is that you have a sequence with a side effect that has been evaluated multiple times.

The first estimate gives the first sequence of random numbers:

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

      

The second call evaluates again, producing a completely different sequence:



let total = numbers |> Seq.sum

      

What you need to do if you want the first evaluation around to run through it multiple times, either materialize the sequence or cache it:

// 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

      

+9


source







All Articles