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

时间:2013-06-03 12:45:44

标签: 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)
    }

如果使用

调用模块中的JsonProvider
[<Literal>]
let sample = """{"name":"Peter","age":9}"""

type provider = JsonProvider<sample>

工作正常。为什么我不能将其作为parameter传递给我?我知道它与编译时清晰的引用有关,但除了声明每个providers explicitly之外,无法弄清楚如何绕过它。

1 个答案:

答案 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

虽然,我并不完全清楚为什么你需要一个类型提供者。提供者的关键是为您提供可用于访问具体数据源的好类型。如果您的converterstorer处理任何 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)
    }