Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/extjs/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
F# 将函数作为参数传递并重载它_F#_Parametric Polymorphism - Fatal编程技术网

F# 将函数作为参数传递并重载它

F# 将函数作为参数传递并重载它,f#,parametric-polymorphism,F#,Parametric Polymorphism,我想对我的函数计时,其中一些函数最多使用三个参数。现在我正在使用下面相同的代码,并对这三个版本进行了一些修改 let GetTime f (args : string) = let sw = Stopwatch.StartNew() f (args) printfn "%s : %A" sw.Elapsed 我想用这个函数替换这三个函数 let GetTime f ( args : 'T[]) = let sW = Stopwatch.StartNew()

我想对我的函数计时,其中一些函数最多使用三个参数。现在我正在使用下面相同的代码,并对这三个版本进行了一些修改

let GetTime f (args : string) = 
    let sw = Stopwatch.StartNew()
    f (args)
    printfn "%s : %A" sw.Elapsed 
我想用这个函数替换这三个函数

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
    ()

但是如果我使用这三个函数,我会得到一个类型不匹配的错误。是否可以将函数作为参数发送并像这样使用它?

您可能正在考虑将一个方法组作为参数传递给
GetTime
,然后让编译器决定调用方法组的哪个重载。这在任何.NET编译器中都是不可能的。方法组由编译器和工具(如ReSharper)用于代码分析,但它们在运行时并不实际存在。

编译器不可能知道在运行时将传递多少个参数,因此函数
f
必须同时满足
't->unit
't->unit
。此表单还要求所有参数的类型相同

let getTime f =
    let sw = Stopwatch.StartNew()
    let result = f ()
    printfn "%A" sw.Elapsed
    result
以下方法延迟函数执行,可能适合您的需要

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" |] ",")

为什么不这样做呢

let getTime f =
    let sw = Stopwatch.StartNew()
    let result = f ()
    printfn "%A" sw.Elapsed
    result
假设
f1
f2
f3
是分别采用1、2和3个参数的三个函数,您可以像这样使用
getTime
函数:

getTime (fun () -> f1 "foo")
getTime (fun () -> f2 "foo" "bar")
getTime (fun () -> f3 "foo" "bar" "baz")
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
但是,如果您只需要对FSI中的某些函数计时,则此功能已经内置:只需键入

> #time;;

如果函数采用元组形式的参数,则会打开计时。

,如下所示:

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
那么实现就变得微不足道了:

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
用法:

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"

这变得有点棘手。这个想法是使用标准运算符
(为什么你不能在
成员
函数上使用多态性呢?我只是想在模块中保持简单。我正在尝试一种功能性更强的方法,没有类型。我知道F#是多半径的,但我想尝试其他方法。请注意,你的问题与运算符重载无关。你描述的是param计量多态性。