2013-12-16 26 views
2

我已經編寫了許多類型爲out_channel -> 'a -> unit的漂亮打印機,現在我想要一段代碼通過使用漂亮的打印機從值中獲取字符串。通過使用漂亮的打印機從值中獲取字符串

舉例來說,我已經實現了以下功能:

type t = 
    { x: int; 
    y: int } 

let co = { x = 4; y = 5 } 

let print (chan: out_channel) (co: t) : unit = 
    Printf.fprintf chan "(%d, %d)" co.x co.y 

我覺得功能Printf.sprintf可以幫助我得到字符串(4, 5)。我試過Printf.sprintf "%a" print co,它在printThis expression has type out_channel -> t -> unit but an expression was expected of type unit -> 'a -> string處給了我一個錯誤。

有沒有人知道如何提醒這條線,或沒有人有一個解決方案,而不是sprintf

回答

3

對於類型檢查的原因,這是不可能直接使用%a在sprintf的格式化指令。 如果你能負擔得起使用Format代替Printf,事情會容易很多:

  • 如果你使用的OCaml 4.01,你直接擁有Format.asprintf,根據該文件,你想要做什麼。
  • 如果您有較早的版本,使用創建格式化程序的臨時緩衝區很容易模擬此行爲。然後您可以寫入此格式化程序,一旦完成,您只需檢索緩衝區的內容。

事實上,你必須使用Format.kfprintf,這樣就可以使用任意的格式化功能:

let sfprintf fmt = 
    let b = Buffer.create 20 in 
    let return fmt = Format.pp_print_flush fmt(); Buffer.contents b in 
    Format.kfprintf return (Format.formatter_of_buffer b) fmt 

    let s = sfprintf "%a" print co 

同樣的技術可以適用於Printf格式化功能,但這裏還有另外一個問題:有沒有從Buffer.t中創建out_channel的方法。我能想到的最接近的方式是依靠Unix模塊的pipe功能:

let sfprintf fmt = 
    let (infd,outfd) = Unix.pipe() in 
    let inc = Unix.in_channel_of_descr infd in 
    Unix.set_nonblock infd; 
    let outc = Unix.out_channel_of_descr outfd in 
    let return outc = 
    Printf.fprintf outc "%!"; 
    let b = Buffer.create 10 in 
    try 
     while true do 
     Buffer.add_char b (input_char inc) done; 
     assert false;  
    with Sys_blocked_io -> 
     Unix.close outfd; Unix.close infd; Buffer.contents b 
    in 
    Printf.kfprintf return outc fmt;; 

let s = sfprintf "%a" print co 
0

我怕我不清楚地瞭解你需要什麼,所以讓我猜:

let prints (co: t) : string = 
    Printf.sprintf "(%d, %d)" co.x co.y 

let print ch co = Printf.fprintf ch "%s" (prints co) 

# print stdout co;; 
(4, 5)- : unit =() 
+0

這不是我想要的。我想我的功能'print'使用... – SoftTimur

+0

我不不認爲這是可能的。如果有人會做你想做的 - 我真的很想看到結果。 – Kakadu