提供的类型是否可以在引号中使用 - 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
的调用,并在那里执行您需要执行的任何特殊操作。很难看出您到底想做什么,但这至少应该为您指明正确的方向。
我想生成一个带有静态函数的类型,然后我可以在使用 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
的调用,并在那里执行您需要执行的任何特殊操作。很难看出您到底想做什么,但这至少应该为您指明正确的方向。