我正在使用FSharp.Data typeproviders
。
我想创建一个具有参数来设置typeprovider's
样本字符串或文件位置的函数。
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>
工作正常。为什么我不能将其作为parameter
传递给我?我知道它与编译时清晰的引用有关,但除了声明每个providers explicitly
之外,无法弄清楚如何绕过它。
答案 0 :(得分:4)
函数不能将静态参数的值作为参数,因为必须在编译时确定该值。这意味着如果你写:
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)来完成任务。
异步阻止。另外,请注意您的代码并非真正异步运行 - 要使其异步,您需要使用let!
操作下载URL:
let SyncIt url parser storer =
async {
let wc = new WebClient()
let! html = wc.AsyncDownloadString(url)
parser html
|> Seq.iter (converter >> storer)
}