F#类型提供程序开发:在提供方法时,如何访问可变数量和类型的参数?

F#类型提供程序开发:在提供方法时,如何访问可变数量和类型的参数?,f#,type-providers,F#,Type Providers,我的问题是: 当我在设计时不知道表达式的数量和类型时,如何将列表中的表达式拼接到引号中? 在底部,我包含了类型提供程序的完整代码。(我已将概念剥离以演示问题。)我的问题出现在以下几行: let func = ProvidedMethod((*...*), InvokeCode = fun args -> <@@ let stringParts = args |> List.mapi (fun i

我的问题是:

当我在设计时不知道表达式的数量和类型时,如何将列表中的表达式拼接到引号中?

在底部,我包含了类型提供程序的完整代码。(我已将概念剥离以演示问题。)我的问题出现在以下几行:

  let func = ProvidedMethod((*...*), InvokeCode = fun args ->
        <@@ let stringParts =
                args
                |> List.mapi (fun i arg -> 
                    if paramTypes.[i] = typeof&lt;int&gt; then
                        sprintf "%i" (%%arg: int)...
我不知道如何编写代码,以便在提供程序设计时不知道参数值的数量和类型时“提取”参数值(尽管它们在编译时是已知的)

当我在设计时确实知道参数的存在和类型时,我可以这样做:

printfn“%A”(%args.[0]:int)

但是我不知道如何从
Expr列表
输入到报价单中的
obj列表

以下是完整的类型提供程序代码:

[<TypeProvider>]
type SillyProviderDefinition(config: TypeProviderConfig) as self = 
    inherit TypeProviderForNamespaces()

let sillyType = ProvidedTypeDefinition(THIS_ASSEMBLY, NAMESPACE, "SillyProvider", Some typeof<obj>)
    do sillyType.DefineStaticParameters([ProvidedStaticParameter("argTypes", typeof<string>)], fun typeName args ->
        let retType = ProvidedTypeDefinition(typeName, Some typeof<obj>)        

        let paramTypes =
            (args.[0] :?> string).Split([|'|'|])
            |> Array.map (function
                | "int" -> typeof<int>
                | "string" -> typeof<string>
                | x -> failwithf "Invalid argType %A. Only string or int permitted" x)
        let parameters =
            paramTypes
            |> Array.mapi (fun i p -> ProvidedParameter(sprintf "arg%i" i, p))
            |> Array.toList

        let func = ProvidedMethod("Stringify", parameters, typeof<string>, IsStaticMethod = true, InvokeCode = fun args ->
            <@@ let stringParts =
                    args
                    |> List.mapi (fun i arg ->
                        if paramTypes.[i] = typeof<int> then
                            sprintf "%i" (%%arg: int)
                        elif paramTypes.[i] = typeof<string> then
                            (%%arg: string)
                        else
                            failwith "Unexpected arg type")
                //printfn "%A" (%%args.[0]: int)
                String.Join("", stringParts) @@>)

        do retType.AddMember func
        do sillyType.AddMember retType
        retType)

    do self.AddNamespace(NAMESPACE, [sillyType])
[]
将SillyProviderDefinition(配置:TypeProviderConfig)键入为self=
继承TypeProviderForNamespaces()
让sillyType=ProvidedTypeDefinition(这个程序集,名称空间,“SillyProvider”,一些typeof)
do sillyType.DefineStaticParameters([ProvidedStaticParameter(“argTypes”,typeof)],有趣的typeName args->
让retType=ProvidedTypeDefinition(typeName,某些typeof)
让参数类型=
(args[0]:?>字符串)。拆分([|'|'|'|])
|>Array.map(函数
|“int”->typeof
|“字符串”->typeof
|x->failwithf“无效的argType%A。只允许字符串或int”x)
let参数=
准类型
|>Array.mapi(乐趣i p->ProvidedParameter(sprintf“arg%i”i,p))
|>数组.toList
让func=ProvidedMethod(“Stringify”,参数,typeof,IsStaticMethod=true,InvokeCode=fun参数->
List.mapi(乐趣i参数->
如果paramTypes.[i]=typeof then
sprintf“%i”(%arg:int)
elif paramTypes.[i]=typeof then
(%arg:字符串)
其他的
故障类型为“意外参数类型”)
//printfn“%A”(%args.[0]:int)
String.Join(“,stringParts)@>)
do retType.AddMember func
do sillyType.AddMember retType
retType)
do self.AddNamespace(命名空间,[sillyType])

作为一个最小的例子,假设我们有带类型的列表和带一些引号的列表(在类型提供程序的上下文中,您有类型列表,
args
是引号列表,可能还包含
实例):

现在,区分所提供的报价代码(报价级别)和生成报价的普通代码(代码级别)中发生了什么很重要。在代码级别,我们迭代所有类型和引用的参数,并生成引用列表,调用
formatt
formatString
——这些类型可以是
Expr
,因为它们具有相同的类型:

let formattedArgList = 
  [ for t, e in List.zip tys args ->
      if t = typeof<int> then <@ formatInt %%e @>
      elif t = typeof<string> then <@ formatString %%e @>
      else failwith "!" ]
现在,您可以使用quoted
String.concat
call构建报价:

<@ String.concat "," %listArgExpr @>


您能告诉我该代码在类型提供程序类的上下文中的位置吗?我尝试合并它,它会编译,但在尝试运行时出现以下错误:
错误FS0193:模块/命名空间。编译单元“TypeProviderPain”中的“$Library1”不包含命名空间、模块或类型formatInt@47“
scripty.fsx(7,9):错误FS1109:对类型“%$Library1”的引用。formatInt@47在程序集中找到了“TypeProviderPain”,但在该程序集中找不到该类型
我可以通过将“formatInt”和“formatString”移动到它们自己的模块来消除此运行时错误。我还需要将“String.concat”替换为“String.Join”以避免类似错误:
错误FS0193:编译单元“FSharp.Core”中的模块/命名空间“Microsoft.FSharp.Collections”不包含命名空间、模块或类型“StringModule”
。在采取这些步骤之后,我能够运行类型提供程序。遗憾的是,这些类型的错误是通常类型提供程序遇到的麻烦。。。很高兴你成功了!
let formatInt (n:int) = string n
let formatString (s:string) = s
let formattedArgList = 
  [ for t, e in List.zip tys args ->
      if t = typeof<int> then <@ formatInt %%e @>
      elif t = typeof<string> then <@ formatString %%e @>
      else failwith "!" ]
let listArgExpr = 
  formattedArgList
  |> List.fold (fun state e -> <@ %e::%state @>) <@ [] @>
<@ String.concat "," %listArgExpr @>