2017-02-07 10 views
1

Можно ли использовать функцию FSharp и преобразовать ее в динамическую функцию, альтернативно, что-то вроде этого подходит к FSharp в будущем?Динамическая функция Вызов в FSharp

let func (a:int) (b:int) : int = 
    a + b 

let dynamicFunc = FSharpFunc.ToDynamicFunc(func) 

let argumentList = [1; 2] 

let object = dynamicFunc argumentList 

let result = object :?> int 

Похоже, что вы в настоящее время, чтобы возвратиться к стандартному отражению (как это: calling a F# function by name), однако, этот подход кажется очень хрупким. Главным образом, потому что нет реальной гарантии, что она работает, и вы должны знать, что происходит под обложками.

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

let wrapFun (x:'f) : 'f = 

    let args = FSharp.Reflection.FSharpType.GetFunctionElements <| x.GetType() 

    let runner (any:obj list) : obj = 
     // Do extra things 
     FSharpFunc.DynamicInvoke x 

    FSharp.Reflection.FSharpValue.MakeFunction (typeof<'f>, runner) :?> 'f 
+5

Не могли бы вы дать более реалистичный вариант использования? Существуют различные способы делать вещи динамически, но я вообще избегал их, если это вообще возможно, потому что они просто облегчают ввод ошибок. В вашем конкретном примере у вас есть функция 'func' со статически известным типом, поэтому ее динамическое обращение не кажется полезным. – kvb

+0

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

ответ

0

F # поддерживает динамический оператор вызова. Но вы должны реализовать свои. Вот пример реализации берется из http://www.fssnip.net/2U/title/Dynamic-operator-using-Dynamic-Language-Runtime

// Reference C# implementation of dynamic operations 
#r "Microsoft.CSharp.dll" 
open System 
open System.Runtime.CompilerServices 
open Microsoft.CSharp.RuntimeBinder 

// Simple implementation of ? operator that works for instance 
// method calls that take a single argument and return some result 
let (?) (inst:obj) name (arg:'T) : 'R = 
    // TODO: For efficient implementation, consider caching of call sites 
    // Create dynamic call site for converting result to type 'R 
    let convertSite = 
    CallSite<Func<CallSite, Object, 'R>>.Create 
     (Binder.Convert(CSharpBinderFlags.None, typeof<'R>, null)) 

    // Create call site for performing call to method with the given 
    // name and a single parameter of type 'T 
    let callSite = 
    CallSite<Func<CallSite, Object, 'T, Object>>.Create 
     (Binder.InvokeMember 
     (CSharpBinderFlags.None, name, null, null, 
      [| CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null); 
      CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) |])) 

    // Run the method call using second call site and then 
    // convert the result to the specified type using first call site 
    convertSite.Target.Invoke 
    (convertSite, callSite.Target.Invoke(callSite, inst, arg)) 

Вы бы иметь возможность использовать его следующим образом

// Dynamically invoke 'Next' method of 'Random' type 
let o = box (new Random()) 
let a : int = o?Next(10) 

Как для Params вы должны передать их в качестве Tuple что-то вроде

target?method(param1, param2), что означало бы, что целевой метод обрабатывает свой аргумент как кортеж и как таковой, может быть или не может быть связано с некоторым сопоставлением шаблонов