gpt4 book ai didi

F# Type Provider development : When providing a method, 如何获取变量个数和类型的参数?

转载 作者:行者123 更新时间:2023-12-04 03:53:18 28 4
gpt4 key购买 nike

我的问题是:

当我在设计时不知道这些表达式的数量和类型时,如何将列表中的表达式拼接成一个引用?

在底部,我包含了类型提供程序的完整代码。 (我已经剥离了这个概念来证明这个问题。)我的问题出现在这些行:

  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)...

在 lambda 参数 arg 上,我得到以下错误:

error FS0446: The variable 'arg' is bound in a quotation but is used as part of a spliced expression. This is not permitted since it may escape its scope.``

我不知道如何编写代码,以便在提供程序设计时不知道值的数量和类型时“提取”参数值(尽管它们在编译时会知道)。

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

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

但我无法弄清楚如何从 Expr list 输入到引用中的 obj list

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

[<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])

最佳答案

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

open Microsoft.FSharp.Quotations

let tys = [ typeof<int>; typeof<string> ]
let args = [ Expr.Value(42); Expr.Value("test"); ]

我们要构造一个调用formatInt 的表达式或 formatString根据类型,然后连接所有格式化字符串:

let formatInt (n:int) = string n
let formatString (s:string) = s

现在,重要的是要区分在提供的引用代码(引用级别)和运行以生成引用的普通代码(代码级别)中发生了什么。在代码级别,我们遍历所有类型和带引号的参数,并通过调用 formatInt 生成引号列表。或 formatString - 可以输入 Expr<string>因为它们具有相同的类型:

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 "!" ]

现在您可以通过调用 fold 来构建列表表达式在代码级别并使用列表 ::引用级别的运算符:

let listArgExpr = 
formattedArgList
|> List.fold (fun state e -> <@ %e::%state @>) <@ [] @>

现在您可以用引用 String.concat 构建报价单调用:

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

关于F# Type Provider development : When providing a method, 如何获取变量个数和类型的参数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43455091/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com