2013-06-03 23 views
3

我正在使用FSharp.Data typeproviders如何將靜態參數傳遞給函數內的f#中的typeprovider

我想做一個函數,它有一個參數設置typeprovider's示例字符串或文件位置。

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

如果有

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

type provider = JsonProvider<sample> 

呼叫時JsonProvider模塊中工作正常。爲什麼我不能通過它作爲parameter?我知道它與編譯時明確的引用有關,但不知道如何繞過它而不是聲明每個providers explicitly

回答

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!操作,下載網址:

let SyncIt url parser storer = 
    async { 
     let wc = new WebClient() 
     let! html = wc.AsyncDownloadString(url) 
     parser html 
     |> Seq.iter (converter >> storer) 
    } 
+0

這是有道理的,謝謝! – Remko

+0

我增加了一些細節。我沒有完全理解爲什麼你需要使用類型提供程序,如果你的'converter'和'storer'可以(顯然)在任何JSON上工作 - 所以它們不會從靜態已知類型中受益.. –

+0

我在第二週f#開始掌握一些概念。我使用typeprovider,因爲我喜歡大多數值類型已被識別。轉換器從DomainTypes.Entity映射到我定義的記錄類型。該記錄存儲在Redis中。在試圖寫一個轉換器時,我不能有多於一種返回類型的事實讓我感到困惑。感謝您的解釋。 Regs,Remko – Remko

相關問題