如何在函数内部的f#中将静态参数传递给typeprovider

Rem*_*mko 3 f# type-providers f#-data

我正在使用FSharp.Data typeproviders

我想制作一个具有参数的函数,该参数设置typeprovider's示例字符串或文件位置。

let SyncIt url sample converter storer =
    async {
        url
        |> MakeRequestAsync 
        |> Async.RunSynchronously
        |> JsonProvider< sample >.Parse
        |> Seq.iter (converter >> storer)
    }
Run Code Online (Sandbox Code Playgroud)

如果使用以下命令调用模块中的JsonProvider

[<Literal>]
let sample = """{"name":"Peter","age":9}"""

type provider = JsonProvider<sample>
Run Code Online (Sandbox Code Playgroud)

工作正常。为什么我不能通过它parameter?我知道它与在编译时清楚引用有关,但是除了声明每个引用之外,其他所有方法都无法解决providers explicitly

Tom*_*cek 5

函数不能将静态参数的值作为参数,因为该值必须在编译时确定。这意味着如果您编写:

let [<Literal>] sample = """{"name":"Peter","age":9}"""
let parseHtml html = JsonProvider<sample>.Parse(html)
Run Code Online (Sandbox Code Playgroud)

...一切都很好,因为编译器知道这sample是一个常量(编译器知道其值),因此可以实例化类型提供程序(在编译过程中)以生成类型。如果您编写如下内容:

let parseHtml sample html = JsonProvider<sample>.Parse(html)
Run Code Online (Sandbox Code Playgroud)

...然后编译器无法知道sample运行时的值,因此无法在编译时生成所需的类型。类型提供程序在运行时不会“存在”,因此无法即时生成类型(这不会真正有用,因为类型提供程序的目的是为您提供一些编译时安全性保证)。

你的例子。在您的情况下,将特定JsonProvider<sample>.Parse函数作为参数可能是有意义的:

let SyncIt url parse storer =
    async {
        url
        |> MakeRequestAsync 
        |> Async.RunSynchronously
        |> parse
        |> Seq.iter (converter >> storer)
    }
Run Code Online (Sandbox Code Playgroud)

这样,调用者可以为类型提供者指定静态参数,然后调用您的函数进行同步:

let [<Literal>] sample = """{"name":"Peter","age":9}"""
SyncIt url (JsonProvider<sample>.Parse) storer
Run Code Online (Sandbox Code Playgroud)

虽然,对我来说还不是很清楚,为什么在这里需要类型提供者。提供程序的重点是为您提供可用于访问具体数据源的漂亮类型。如果你converterstorer对工作的任何 JSON数据文件,那么你可能能够获得使用刚刚做的事情JSON解析器(也是F#数据)

异步块。另外,请注意,您的代码并非真正异步运行-要使其异步,您需要使用以下let!操作下载URL :

let SyncIt url parser storer =
    async {
        let wc = new WebClient() 
        let! html = wc.AsyncDownloadString(url)
        parser html
        |> Seq.iter (converter >> storer)
    }
Run Code Online (Sandbox Code Playgroud)