2014-03-31 33 views
3

我正在試圖打包sprintf函數的調用。這裏是我的嘗試:魔術sprintf函數 - 如何包裝它?

let p format args = "That was: " + (sprintf format args) 

let a = "a" 
let b = "b" 

let z1 = p "A %s has invalid b" a 

這似乎是工作,輸出

val p : format:Printf.StringFormat<('a -> string)> -> args:'a -> string 
val a : string = "a" 
val b : string = "b" 
val z1 : string = "That was: A a has invalid b" 

,但它不會有一個以上的ARG工作:

let z2 = p "A %s has invalid b %A" a b 

我得到編譯時錯誤:

let z2 = p "A %s has invalid b %A" a b;; 
---------^^^^^^^^^^^^^^^^^^^^^^^^^^^ 

stdin(7,10): error FS0003: This value is not a function and cannot be applied 

我該怎麼辦cre吃了一個單一的功能,可以處理任何數量的參數?

UPD。 Tomas建議使用

let p format = Printf.kprintf (fun s -> "This was: " + s) format 

確實有效。這裏有一個例子

let p format = Printf.kprintf (fun s -> "This was: " + s) format 

let a = p "something like %d" 123 
// val p : format:Printf.StringFormat<'a,string> -> 'a 
// val a : string = "This was: something like 123" 

但事實是,我的函數的主要目的是做了一些工作,除了formatring,所以我嘗試如下

let q format = 
    let z = p format // p is defined as suggested 
    printf z // Some work with formatted string 

let z = q "something like %d" 123 

使用建議的代碼和它doesn」 t再次工作:

let z = q "something like %d" 123;; 
    ----------^^^^^^^^^^^^^^^^^^^ 

stdin(30,15): error FS0001: The type ''c -> string' is not compatible with the type 'Printf.TextWriterFormat<('a -> 'b)>' 

我該如何解決它?

回答

6

對於這個工作,你需要使用柯里 - 你的函數p需要採取format,並通過返回的printf功能之一(然後可以採取一個或多個參數的函數)返回的功能。

這不能使用sprintf(因爲那時你將不得不明確地傳播參數。但是,您可以使用kprintf這需要一個延續作爲第一個參數::

let p format = Printf.kprintf (fun s -> "This was: " + s) format 

的延續,是完成用格式化的字符串調用,所以你可以做任何你需要的結果字符串在返回之前

編輯:要回答你的擴展問題,訣竅是把所有additi onal work into the continuation:

let q format = 
    let cont z = 
    // Some work with formatted string 
    printf "%s" z 
    Printf.kprintf cont format 
+0

+1謝謝你的建議。我的情況有點複雜。你可以看看關於這個問題的更新嗎? – Rustam

+0

主要問題是我沒有看到像「xxx%s」這樣的字符串是如何轉換爲「StringFormatter」類的,以及當我寫入'printfn「%」12'時到底發生了什麼。也許你有任何鏈接解釋? – Rustam

+0

@Rustam - 您必須將所有您想要對格式化的字符串進行的工作放在後面。請參閱擴展示例。 –