使用漂亮的打印机从值中获取字符串

时间:2013-12-16 10:49:13

标签: types ocaml

我已经编写了许多类型为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以外的解决方案?

2 个答案:

答案 0 :(得分:3)

出于类型检查的原因,无法在sprintf的格式化指令中直接使用%a。 如果您能够使用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格式化功能,但此处还有另一个问题:无法从out_channel创建Buffer.t。我能想到的最接近的方法是依靠pipe模块的Unix函数:

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

答案 1 :(得分: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 = ()