Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/fsharp/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
Dynamic F#动态运算符,允许访问函数和函数名_Dynamic_F# - Fatal编程技术网

Dynamic F#动态运算符,允许访问函数和函数名

Dynamic F#动态运算符,允许访问函数和函数名,dynamic,f#,Dynamic,F#,给定许多函数,test1,test2。。。属于某个模块: module Checks = let test1 x = ... let test2 x = ... ... 如何使用(?)运算符访问函数名和函数本身?结果应该如下所示: let name, func = Checks?test1 assert(name = "test1") assert(func(x) = Checks.test1(x)) //whatever x is (test1 is known to

给定许多函数,
test1
test2
。。。属于某个模块:

module Checks =
    let test1 x = ...
    let test2 x = ...
    ...
如何使用(?)运算符访问函数名和函数本身?结果应该如下所示:

let name, func = Checks?test1
assert(name = "test1")
assert(func(x) = Checks.test1(x)) //whatever x is (test1 is known to be pure)

您不能使用
运算符访问模块中的函数,因为构造
检查?test1
在语法上不正确(这将转换为
(?)检查“test”
,并且您不能使用模块名称作为值)

但是,对于使用对象实例的类型成员(例如,
obj?test
),应该可以这样做。或者,您可以编写一个“假”对象实例(知道模块的名称)。
的实现随后将查找模块并搜索模块中的静态成员

最简单的实现(第一种情况)如下所示:

let (?) obj s = 
  let memb = obj.GetType().GetMethod(s)
  // Return name and a function that runs the method
  s, (fun args -> memb.Invoke(obj, args))

// Type that contains tests as members    
type Check() = 
  member x.test1 () = 32

// We need to create instance in order to use '?'
let ch = Check()
let s,f = ch?test1

// Function 'f' takes array of objects as an argument and
// returns object, so the call is not as elegant as it could be
let n = ((f [| |]) :?> int)

您还可以添加一些包装,使函数“f”变得更好一些,但我希望这能说明这一点。不幸的是,这对模块不起作用。

您不能使用
操作符访问模块中的函数,因为构造
检查?test1
在语法上不正确(这将转换为
(?)检查“test”
,并且您不能使用模块名称作为值)

但是,对于使用对象实例的类型成员(例如,
obj?test
),应该可以这样做。或者,您可以编写一个“假”对象实例(知道模块的名称)。
的实现随后将查找模块并搜索模块中的静态成员

最简单的实现(第一种情况)如下所示:

let (?) obj s = 
  let memb = obj.GetType().GetMethod(s)
  // Return name and a function that runs the method
  s, (fun args -> memb.Invoke(obj, args))

// Type that contains tests as members    
type Check() = 
  member x.test1 () = 32

// We need to create instance in order to use '?'
let ch = Check()
let s,f = ch?test1

// Function 'f' takes array of objects as an argument and
// returns object, so the call is not as elegant as it could be
let n = ((f [| |]) :?> int)

您还可以添加一些包装,使函数“f”变得更好一些,但我希望这能说明这一点。不幸的是,这不适用于模块。

以下是一些示例代码,展示了其中的一些功能。我使用
D
作为
检查
模块加函数名的“动态”访问

module Checks = 
    let test1(x) = printfn "test1 %d" x
    let test2(x,y) = printfn "test2 %s %d" x y

type MyDynamic() = class end
let D = new MyDynamic()
let (?) (md:MyDynamic) fname : (string * ('a -> 'r)) =
    let a = md.GetType().Assembly
    let t = a.GetType("Program+Checks")
    let m = t.GetMethod(fname)
    let f arg = 
        let at = arg.GetType()
        let fsharpArgs = 
            if at.IsGenericType && at.GetGenericTypeDefinition().FullName.StartsWith("System.Tuple`") then
                Microsoft.FSharp.Reflection.FSharpValue.GetTupleFields(arg)
            else
                [| box arg |]
        unbox(m.Invoke(null, fsharpArgs))
    fname, f

let Main() =
    let x = 42
    let s = "foo"
    let name, func = D?test1 
    assert(name = "test1") 
    assert(func(x) = Checks.test1(x))

    let name, func = D?test2
    assert(name = "test2") 
    assert(func(s,x) = Checks.test2(s,x))

    System.Console.ReadKey()

Main()

下面是一些示例代码,展示了其中的一些内容。我使用
D
作为
检查
模块加函数名的“动态”访问

module Checks = 
    let test1(x) = printfn "test1 %d" x
    let test2(x,y) = printfn "test2 %s %d" x y

type MyDynamic() = class end
let D = new MyDynamic()
let (?) (md:MyDynamic) fname : (string * ('a -> 'r)) =
    let a = md.GetType().Assembly
    let t = a.GetType("Program+Checks")
    let m = t.GetMethod(fname)
    let f arg = 
        let at = arg.GetType()
        let fsharpArgs = 
            if at.IsGenericType && at.GetGenericTypeDefinition().FullName.StartsWith("System.Tuple`") then
                Microsoft.FSharp.Reflection.FSharpValue.GetTupleFields(arg)
            else
                [| box arg |]
        unbox(m.Invoke(null, fsharpArgs))
    fname, f

let Main() =
    let x = 42
    let s = "foo"
    let name, func = D?test1 
    assert(name = "test1") 
    assert(func(x) = Checks.test1(x))

    let name, func = D?test2
    assert(name = "test2") 
    assert(func(s,x) = Checks.test2(s,x))

    System.Console.ReadKey()

Main()