Динамический оператор F #, дающий доступ как к функции, так и к имени функции - PullRequest
0 голосов
/ 05 июля 2010

Учитывая количество функций 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)

Ответы [ 2 ]

3 голосов
/ 05 июля 2010

Вы не можете использовать оператор ? для доступа к функциям в модуле, потому что конструкция Checks?test1 не синтаксически верна (это будет переведено в (?) Checks "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)

YouМожно также добавить некоторые обертки, чтобы сделать функцию 'f' немного лучше, но я надеюсь, что это демонстрирует идею.К сожалению, это не может работать для модулей.

1 голос
/ 05 июля 2010

Вот пример кода, который демонстрирует некоторые из них. Я использую D в качестве «динамического» доступа для модуля Checks и имени функции.

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()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...