提供的类型是否可以在引号中使用 - TypeProvider 调用是否出现在 ReflectedDefinition 函数中?

Can a provided type be used in a quotation - Do TypeProvider calls appear in ReflectedDefinition functions?

我想生成一个带有静态函数的类型,然后我可以在使用 ReflectedDefinition 属性成为引用的函数中使用它。在我看来,这是一种将某些东西转换为 FSharp 类型的便捷方法,使用 FSharp 组合函数和类型的域,并将组合的代码吐回其原始形式,并获得了类型检查、VS 智能感知、高阶函数的好处等。为了尝试开始,我有这种类型的提供程序,主要是 copy->pasted 来自各种文章

[<TypeProvider>]
type CSoundTypeProvider(config: TypeProviderConfig) as this = 

    inherit ProvidedTypes.TypeProviderForNamespaces()

    let namespaceName = "TestNamespace"
    let thisAssembly = Assembly.GetExecutingAssembly()

//    config.

    let intType = typeof<int>
    let providedParam = ProvidedTypes.ProvidedParameter("prm", intType)
    let providedFunction = ProvidedTypes.ProvidedMethod("TestMethod", [providedParam], intType, IsStaticMethod=true
                                    , InvokeCode = fun args -> 
                                                  // The 'args' parameter represents expressions that give us access to the 
                                                  // instance on which the method is invoked and other parameters (if there are more)
                                                  let instance = args.[0]
                                                  // Now we can return quotation representing a call to MethodInfo 'p' with 'instance'
                                                  instance)
    let csoundProvidedWrapper = ProvidedTypes.ProvidedTypeDefinition(thisAssembly, namespaceName, "TestType", None)
    do csoundProvidedWrapper.AddMember(providedFunction)
    do this.AddNamespace(namespaceName, [csoundProvidedWrapper])

并使用此反映的定义对其进行测试:

[<ReflectedDefinition>]
let myfn i j =
    let k = i * j
    let x = k + 2
    let f = TestNamespace.TestType.TestMethod k
    let ret = f + 2
    ret

我正在像这样解析反映的定义:

<@ myfn @> |> println

println 是一个函数(从另一篇文章复制而来),它具有许多用于解析引用的活动模式,例如 Patterns.Call(None, DerivedPatterns.MethodWithReflectedDefinition(n), expList),这让我得到了所有代码的表达式树,except 对于提供的静态方法。我正在尝试做的事情有可能吗?如果是这样,我可能在此处的 println 函数中遗漏了什么活动模式:

let println expr =
    let rec print expr = match expr with
        | Patterns.Application(expr1, expr2) ->
            // Function application.
            print expr1
            printf " "
            print expr2
        | Patterns.Call(None, DerivedPatterns.MethodWithReflectedDefinition(n), expList) ->
            print n
        | Patterns.Call(exprOpt, methodInfo, exprList) ->
            // Method or module function call.
            match exprOpt with
            | Some expr -> print expr
            | None -> printf "%s" methodInfo.DeclaringType.Name
            printf ".%s(" methodInfo.Name
            if (exprList.IsEmpty) then printf ")" else
            print exprList.Head
            for expr in exprList.Tail do
                printf ","
                print expr
            printf ")"
        | DerivedPatterns.Int32(n) ->
            printf "%d" n
        | Patterns.Lambda(param, body) ->
            // Lambda expression.
            printf "fun (%s:%s) -> " param.Name (param.Type.ToString())
            print body
        | Patterns.Let(var, expr1, expr2) ->
            // Let binding.
            if (var.IsMutable) then
                printf "let mutable %s = " var.Name
            else
                printf "let %s = " var.Name
            print expr1
            printf " in "
            print expr2
        | Patterns.PropertyGet(_, propOrValInfo, _) ->
            printf "%s" propOrValInfo.Name
        | DerivedPatterns.String(str) ->
            printf "%s" str
        | Patterns.Value(value, typ) ->
            printf "%s" (value.ToString())
        | Patterns.Var(var) ->
            printf "%s" var.Name
        | _ -> printf "%s" (expr.ToString())
    print expr

如果我不能这样做,您会推荐什么方法来生成我可以在引号中使用的 FSharp 定义?我在很大程度上受到了 FunScript 项目的影响,但希望避免似乎每个 Typescript 定义都必须编译成单独的 DLL 的步骤。

大多数类型提供程序演示都使用 擦除类型提供程序,它们不会生成实际的 .NET 类型。当您使用擦除类型提供程序时,生成的方法将被 擦除 并替换为您在方法的 InvokeCode 中提供的代码。

假设您有一个方法 Foo"Foo" 作为参数擦除到 someFunc

myObj.Foo()   ~>    someFunc(myObj, "Foo")

在引文中,您还会看到已删除的版本(直接 <@ .. @>ReflectedDefinition):

<@ myObj.Foo() @>  ~> <@ someFunc(myObj, "Foo") @>

FunScript 类型提供程序的工作方式是它生成一些包含函数名称的虚拟代码,以便它可以生成相应的 JavaScript。假设您有:

<@ win.Alert(arg) @> ~> <@ invokeFunction("alert", win, arg) @>

要做同样的事情,您需要定义一个像 invokeFunction 的函数并生成适当的 InvokeCode。然后,您可以在生成的报价单中查找对 invokeFunction 的调用,并在那里执行您需要执行的任何特殊操作。很难看出您到底想做什么,但这至少应该为您指明正确的方向。