我正在使用FSharp.Data typeproviders
。
我想创建一个具有参数的函数,用于设置typeprovider的
示例字符串或文件位置。
let SyncIt url sample converter storer =
async {
url
|> MakeRequestAsync
|> Async.RunSynchronously
|> JsonProvider< sample >.Parse
|> Seq.iter (converter >> storer)
}
如果调用模块中的 JsonProvider
[<Literal>]
let sample = """{"name":"Peter","age":9}"""
type provider = JsonProvider<sample>
工作正常。为什么我不能将其作为参数
传递?我知道这与编译时的引用清晰有关,但除了显式声明每个提供程序
之外,无法弄清楚如何解决它。
最佳答案
函数不能将静态参数的值作为参数,因为该值必须在编译时确定。这意味着如果你写:
let [<Literal>] sample = """{"name":"Peter","age":9}"""
let parseHtml html = JsonProvider<sample>.Parse(html)
...一切都很好,因为编译器知道 sample
是一个常量(编译器知道它的值),因此它可以实例化类型提供程序(在编译期间)以生成类型。如果你写这样的内容:
let parseHtml sample html = JsonProvider<sample>.Parse(html)
...那么编译器无法知道 sample
的值是多少可能是在运行时,因此它无法在编译时生成所需的类型。类型提供程序在运行时并不“存在”,因此无法即时生成类型(这并不是真正有用,因为类型提供程序的目的是为您提供一些编译时安全保证)。
您的示例。在您的情况下,采用特定的 JsonProvider<sample>.Parse
可能是有意义的而是将函数作为参数:
let SyncIt url parse storer =
async {
url
|> MakeRequestAsync
|> Async.RunSynchronously
|> parse
|> Seq.iter (converter >> storer)
}
这样,调用者可以将静态参数指定给类型提供程序,然后调用您的函数来进行同步:
let [<Literal>] sample = """{"name":"Peter","age":9}"""
SyncIt url (JsonProvider<sample>.Parse) storer
尽管如此,我并不完全清楚为什么这里需要类型提供程序。提供者的目的是为您提供良好的类型,您可以使用它们来访问具体的数据源。如果您converter
和storer
处理任何 JSON 数据文件,那么您可能只需使用 JSON parser (also in F# Data) 就能完成任务.
异步 block 。另外,请注意,您的代码并不是真正异步运行 - 要使其异步,您需要使用 let!
下载 URL操作:
let SyncIt url parser storer =
async {
let wc = new WebClient()
let! html = wc.AsyncDownloadString(url)
parser html
|> Seq.iter (converter >> storer)
}
关于f# - 如何在函数内将静态参数传递给 f# 中的类型提供程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16897051/