我希望生成一个带有静态函数的类型,然后在使用ReflectedDefinition属性成为引号的函数中使用它。在我看来,这是一种将某些内容转换为FSharp类型的方便方法,它使用FSharp来组合函数和类型的域,并将组合的代码返回到其本机形式,它得到了类型检查、VS intellisense、高级函数等的好处。为了开始工作,我有了这个类型提供程序,主要是复制>粘贴在各种文章中。
[<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 @> |> printlnDerivedPatterns.MethodWithReflectedDefinition(n),是一个函数(从另一篇文章中复制),它具有许多用于解析引用的活动模式,比如Patterns.Call(None,Patterns.Call expList),它为我提供了所有代码的扩展树,除了提供的静态方法。我想做的事有可能吗?如果是这样的话,在这里我可能忽略了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项目的影响,但我希望避免这样的步骤:似乎每个类型记录定义都必须编译成一个独立的DLL。
发布于 2015-11-07 21:59:35
大多数类型提供程序演示使用擦除的类型提供程序,这些提供程序不生成实际的.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的调用,并在那里做任何需要做的特殊事情。很难看出你到底想要做什么,但这至少会给你指明正确的方向。
https://stackoverflow.com/questions/33577558
复制相似问题