Jack Chidley
Jack Chidley

Reputation: 136

Running a function with recursion F#

I am doing something really basic wrong, but I can't, for the life of me, work out what it is...

    let rec testItSeveralTimes (test, times) =
        printfn "Iterations to go %O" times
        match times with
            | 0 -> ()
            | _ -> 
                test
                testItSeveralTimes (test, (times - 1))

     testItSeveralTimes ((printfn "Running a test"), 2)

What I expect is:

Iterations to go 2
Running a test
Iterations to go 1
Running a test
Iterations to go 0
Running a test
val it : unit = ()

What I get is:

Running a test
Iterations to go 2
Iterations to go 1
Iterations to go 0
val it : unit = ()

It seems like the function is being evaluated once, at the beginning, and then ignored.

This question (Wrapping a function with an indeterminate number of parameters in F#) seemed to have an answer, but no.

Upvotes: 0

Views: 74

Answers (2)

Grundoon
Grundoon

Reputation: 2764

If you extract out the test parameter into a separate step, the problem becomes obvious:

let test = printfn "Running a test"
// expression has run and printed already!
// value of "test" is a simple value (unit) now
testItSeveralTimes (test, 2)

As part of evaluating the let test = expression, the printfn function is run immediately.

Then, test is assigned the value (), which is the output of printfn

Inside testItSeveralTimes, the value of test is just there, but doesn't do anything.

As John said, you need to make the test parameter be a function that can be run:

let rec testItSeveralTimes (test, times) =
    printfn "Iterations to go %O" times
    match times with
        | 0 -> ()
        | _ -> 
            test()  // test parameter is now a function
            testItSeveralTimes (test, (times - 1))

With this change, you also need to define the test value as a function that is not run immediately:

let test() = printfn "Running a test"
// value of test is a function and is not run yet
testItSeveralTimes (test, 2)

As a general rule, if you are having problems understanding what is going, try breaking out all the steps into separate values like this -- it makes it easier to debug, because you can evaluate each one in turn (in F# Interactive or REPL) and see what happens!

Upvotes: 5

John Palmer
John Palmer

Reputation: 25516

Here test has a value of unit.

You want something like

testItSeveralTimes ((fun _ -> printfn "Running a test"), 2)

and change the usage to

test()

Upvotes: 2

Related Questions