Function passing and overloading

I want to use my functions, some of them use up to three parameters. Right now I am using the same code below with some options for three.

let GetTime f (args : string) = 
    let sw = Stopwatch.StartNew()
    f (args)
    printfn "%s : %A" sw.Elapsed 

      

I want to replace three functions with this.

let GetTime f ( args : 'T[]) =
    let sW = Stopwatch.StartNew()
    match args.Length with
    | 1 -> f args.[0]
    | 2 -> f (args.[0] args.[1])
    printfn "%A" sW.Elapsed
    ()

      

But I get a type mismatch error if I use three functions it works. Is it possible to send a function as a parameter and use it like that?

+3


source to share


4 answers


The compiler does not know how many arguments will be passed at run time, so the function f

must satisfy both 'T -> unit

and 'T -> 'T -> unit

. This form also requires all arguments to be of the same type.

The following approach delays the function and may be suitable for your needs.



let printTime f =
    let sw = Stopwatch.StartNew()
    f() |> ignore
    printfn "%A" sw.Elapsed

let f1 s = String.length s
let f2 s c = String.concat c s

printTime (fun () -> f1 "Test")
printTime (fun () -> f2 [| "Test1"; "Test2" |] ",")

      

+4


source


Why not just do something like this?

let getTime f =
    let sw = Stopwatch.StartNew()
    let result = f ()
    printfn "%A" sw.Elapsed
    result

      

Assuming that f1

, f2

and f3

are the three functions, which take respectively 1, 2 and 3 of the argument, you can use the getTime

following:

getTime (fun () -> f1 "foo")
getTime (fun () -> f2 "foo" "bar")
getTime (fun () -> f3 "foo" "bar" "baz")

      



However, if you just need to use some of the functions in FSI, this function is already built in: just type

> #time;;

      

and the time will be included.

+5


source


You are probably thinking about passing a method group as an argument to GetTime

, and then when the compiler decides what overload the method group is calling. This is not possible with any .NET compiler. Method groups are used for code analysis by compilers and tools such as ReSharper, but they are not what actually exists at runtime.

+2


source


If your functions take their arguments in a form like this:

let f1 (s: string, b: bool) =
    System.Threading.Thread.Sleep 1000
    s

let f2 (n: int, s:string, dt: System.DateTime) =
    System.Threading.Thread.Sleep 1000
    n+1

      

then the implementation becomes trivial:

let Timed f args =
    let sw = System.Diagnostics.Stopwatch.StartNew()
    let ret = f args
    printfn "Called with arguments %A, elapsed %A" args sw.Elapsed 
    ret

      

Using:

f1
|> Timed // note, at this time we haven't yet applied any arguments
<| ("foo", true)
|> printfn "f1 done, returned %A"

f2
|> Timed
<| (42, "bar", DateTime.Now)
|> printfn "f2 done, returned %A"

      

However, if the functions take their arguments in curry form, like this:

let f1Curried (s: string) (b: bool) =
    System.Threading.Thread.Sleep 1000
    s

let f2Curried (n: int) (s:string) (dt: System.DateTime) =
    System.Threading.Thread.Sleep 1000
    n+1

      

it gets a little tricky. The idea is to use the standard operators (<|)

, (<||)

and (<|||)

, to pivot arguments.

let Timed2 op f args =
    let sw = System.Diagnostics.Stopwatch.StartNew()
    let ret = op f args
    printfn "Called with arguments %A, elapsed %A" args sw.Elapsed 
    ret

f1Curried
|> Timed2 (<||) // again, no arguments are passed yet
<| ("foo", true)
|> printfn "f1Curried done, returned %A"

f2Curried
|> Timed2 (<|||)
<| (42, "bar", DateTime.Now)
|> printfn "f2Curried done, returned %A"

      

+2


source







All Articles