GWLlosa
GWLlosa

Reputation: 24403

How can I embed a function call inside another function?

So I have a function that I've pulled from a tutorial:

let sumOfSquares nums = 
    nums
    |> Seq.map sqr
    |> Seq.sum

I have decided that I want to test its performance. In a brute-force approach, I would do something like:

let timeFunction nums =
    let sw = new System.Diagnostics.Stopwatch()
    sw.Start()
    nums
        |> Seq.map sqr
        |> Seq.sum
    sw.Stop()
    sw.ElapsedMilliseconds

However, this struck me as a good example for how F# is supposed to treat functions as first-class citizens. So I tried to do something like the following, instead:

let timeFunction fn x =
    let sw = new System.Diagnostics.Stopwatch()
    sw.Start()
    fn x
    sw.Stop()
    sw.ElapsedMilliseconds

And then I tried to call it:

let sequenceOfNums = [for i in 1..20 -> i]
let print n = System.Console.WriteLine(n.ToString())
print "Time Trial"
print (timeFunction sumOfSquares sequenceOfNums)

However, this fails with the following error:

Type mismatch. Expecting a 'a -> unit but given a 'a -> int The type 'unit' does not match the type 'int'

on the line that calls the function. Do I have some sort of syntactical error here, or have I grossly misunderstood a concept?

Upvotes: 2

Views: 160

Answers (1)

Daniel
Daniel

Reputation: 47904

Because the result of fn isn't being used it's inferred to be unit. You can fix this by piping the result to the ignore function. It's signature is 'a -> unit, so it makes the return type of fn generic (which is what you want).

let timeFunction fn x =
    let sw = new System.Diagnostics.Stopwatch()
    sw.Start()
    fn x |> ignore
    sw.Stop()
    sw.ElapsedMilliseconds

Upvotes: 4

Related Questions