4

我正在使用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?我知道这与在编译时明确引用有关,但除了声明 each 之外无法弄清楚如何解决它providers explicitly

4

1 回答 1

8

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

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

虽然,我并不完全清楚为什么在这里需要类型提供程序。提供者的目的是为您提供可用于访问具体数据源的好类型。如果您使用任何converterJSON 数据文件,那么您可能只使用JSON 解析器(也在 F# Data 中)来完成工作。storer

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

let SyncIt url parser storer =
    async {
        let wc = new WebClient() 
        let! html = wc.AsyncDownloadString(url)
        parser html
        |> Seq.iter (converter >> storer)
    }
于 2013-06-03T13:40:15.463 回答