2011-07-06 45 views
7

printf,fprintf等:全部接受%a轉換。OCaml中的用戶定義打印機

的手冊%a說:

「用戶定義的打印機採用兩個參數,並應用第一個outchan中(電流輸出信道)和第二個參數因此,第一個參數必須具備的。輸入out_channel - >'b - >單元,然後輸入第二個'b',函數產生的輸出因此會插入當前點的fprintf輸出中。「

我無法理解用戶定義的打印機的用途以及如何實現和使用它。有人可以解釋動機並提供一個例子嗎?例如,當你想要打印一個複雜的數據結構時,爲什麼不能直接將自定義函數的數據結構打印到字符串或輸出?

+0

'sprintf'和'ksprintf'採取單位的'功能 - >「A - >字符串不像你提到的功能。 – nlucaroni

+0

我的問題可能很不精確。我想知道的是,在什麼情況下,人們應該更喜歡使用'%a'而不是僅僅打印到一個字符串(使用'printf'和'%s'或'sprintf'或'ksprintf'等)並且然後使用該字符串執行其他操作 - 例如在通道上輸出。 – ndbd

回答

2

如果你有一個函數TY-> string,你可以用它來與"%s"打印您的數據,所以我覺得在現實的情況下,你可以「只打印你的數據結構」。代替使用"%a"可能是一種風格選擇。它在某些方面似乎更加一致。

在32位系統上,字符串長度限制在16MB左右。所以你可以想象一下"%a"會工作而"%s"會失敗的情況:如果中間字符串比這個更長。不過,我從來沒有在實踐中出現這種情況。我自己就用"%s"

5

你是什麼意思的「只是打印複雜的數據結構」?一旦你定義了一個將你的數據結構轉換爲字符串的函數,你可以這樣做。也可以用「默認表示」(參見http://caml.inria.fr/cgi-bin/hump.en.cgi?sort=0&browse=139)「轉儲」數據結構,但這比調試更重要。

說了這麼多;爲%a一個很簡單的例子:

type ty = A | B 

let ty_to_string = function 
    | A -> "A" 
    | B -> "B" 

let print_ty chan v = output_string chan (ty_to_string v) 

let _ = Printf.printf "%a" print_ty A 
+0

我不理解的是爲什麼人們更喜歡這個,比如說 讓_ = Printf.printf「%s」(ty_to_string A)或 讓_ = Printf.fprintf stdout「%s」(ty_to_string A)。至少後者給出了某種抽象方法來打印哪個通道,類似於在上面的例子中使用%a? – ndbd

+2

事情是,對於較大的結構轉換爲字符串可能是昂貴的(想想:字符串連接)。如果可能的話,直接寫入頻道會更有效率。當你有這樣的功能時,'%a'自然就會出現。 – akoprowski

1

使用%a可以讓打印直接進入輸出通道,而不是「%s」並將要打印的值串化並打印出來。

這種區別看起來完全是效率問題 - 爲什麼當將串行化數據直接發送到輸出通道是可能和合理的時候,爲什麼要分配一個潛在的大字符串(或者使用緩衝區,並進行指數大小調整和複製) ? Jeffrey非常正確地指出,由於字符串長度的原因,非常大的串行化可能會在32位系統上失敗。

我用%a常常在我的代碼,使用電池組合的打印功能來創建自定義打印機對我的價值觀:

let range_print oc r = 
    let print_one oc (a,b) = fprintf oc "%d:%d" a b in 
    List.print ~first:"" ~last:"" ~sep:"," print_one oc r 
let print_rule print_pred print_dec oc r = 
    fprintf oc "%a,%a" print_pred r.pred print_dec r.dec 
let print_item oc x = print_rule range_print Int.print oc x in 
... 
printf "IN : %a\nOUT: %a\n" print_item a print_item b;