2014-11-21 4 views
3

Я хочу, чтобы мои функции выполнялись, некоторые из них используют до трех параметров. Сейчас я использую тот же код ниже с некоторыми вариантами для трех.Передача функции в качестве параметра и перегрузка

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

Но я получаю ошибку несоответствия типа, если я использую три функции, которые она работает. Можно ли отправить функцию в качестве параметра и использовать ее так?

+0

Почему вы не можете использовать полиморфизм для функций 'member'? –

+0

Я просто хотел сохранить его простым в модуле. Я пытаюсь пойти на более функциональный подход, без типов. Я знаю, что F # - многопарадигма, но я хотел попробовать другой подход. – EinsL

+0

Просто обратите внимание, что ваш вопрос не имеет ничего общего с перегрузкой оператора. То, что вы описываете, является параметрическим полиморфизмом. – mydogisbox

ответ

4

Компилятор не может знать, сколько аргументов будет передано во время выполнения, поэтому функция f должна удовлетворять как 'T -> unit, так и 'T -> 'T -> unit. Эта форма также требует, чтобы все аргументы были одного типа.

Следующий подход задерживает выполнение функции и может быть подходящим для ваших нужд.

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

Возможно, вы думаете о передаче группы методов в качестве аргумента GetTime, а затем, когда компилятор решит, какую перегрузку вызывает группа методов. Это невозможно с любым компилятором .NET. Группы методов используются для анализа кода компиляторами и инструментами, такими как ReSharper, но они не являются тем, что действительно существует во время выполнения.

5

Почему бы просто не сделать что-нибудь подобное?

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

Однако, если вы просто необходимо выполнить некоторые функции в FSI, эта функция уже встроена: только тип

> #time;; 

и timi ng будет включен.

2

Если функции принимают их аргументы в tupled формы, подобные этим:

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" 

Однако, если функции принимают свои аргументы в кэрри форму, как это:

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 

становится немного сложнее. Идея заключается в использовании стандартных операторов (<|), (<||) и (<|||), которые предназначены для uncurry аргументов.

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" 
Смежные вопросы