String Formatting in OCaml

OCaml provides excellent support for string formatting, similar to the printf tradition. Here are some examples of common string formatting tasks.

(* Define a simple record type *)
type point = { x : int; y : int }

let main () =
  (* Create an instance of our point record *)
  let p = { x = 1; y = 2 } in

  (* OCaml uses Printf.printf for formatted printing *)
  Printf.printf "record1: %s\n" (string_of_point p);

  (* To include field names, we can define a custom function *)
  Printf.printf "record2: { x: %d; y: %d }\n" p.x p.y;

  (* For a representation similar to OCaml syntax *)
  Printf.printf "record3: { x = %d; y = %d }\n" p.x p.y;

  (* To print the type of a value, use '%a' with Obj.magic *)
  Printf.printf "type: %s\n" (Obj.magic p);

  (* Formatting booleans *)
  Printf.printf "bool: %B\n" true;

  (* Integer formatting *)
  Printf.printf "int: %d\n" 123;

  (* Binary representation *)
  Printf.printf "bin: %s\n" (String.init 32 (fun i -> if (14 lsr (31 - i)) land 1 = 1 then '1' else '0'));

  (* Character corresponding to an integer *)
  Printf.printf "char: %c\n" (Char.chr 33);

  (* Hexadecimal encoding *)
  Printf.printf "hex: %x\n" 456;

  (* Float formatting *)
  Printf.printf "float1: %f\n" 78.9;

  (* Scientific notation *)
  Printf.printf "float2: %e\n" 123400000.0;
  Printf.printf "float3: %E\n" 123400000.0;

  (* String formatting *)
  Printf.printf "str1: %s\n" "\"string\"";

  (* OCaml doesn't have a direct equivalent to %q, but we can use %S *)
  Printf.printf "str2: %S\n" "\"string\"";

  (* Hexadecimal representation of a string *)
  Printf.printf "str3: %s\n" (String.init (String.length "hex this") (fun i -> Printf.sprintf "%02x" (Char.code "hex this".[i])));

  (* Pointer representation *)
  Printf.printf "pointer: %s\n" (string_of_int (Obj.magic p));

  (* Width specification for integers *)
  Printf.printf "width1: |%6d|%6d|\n" 12 345;

  (* Width and precision for floats *)
  Printf.printf "width2: |%6.2f|%6.2f|\n" 1.2 3.45;

  (* Left-justified width for floats *)
  Printf.printf "width3: |%-6.2f|%-6.2f|\n" 1.2 3.45;

  (* Width for strings *)
  Printf.printf "width4: |%6s|%6s|\n" "foo" "b";

  (* Left-justified width for strings *)
  Printf.printf "width5: |%-6s|%-6s|\n" "foo" "b";

  (* sprintf returns a string without printing *)
  let s = Printf.sprintf "sprintf: a %s" "string" in
  print_endline s;

  (* Printing to stderr *)
  Printf.fprintf stderr "io: an %s\n" "error"

(* Helper function to convert point to string *)
and string_of_point p =
  Printf.sprintf "{%d %d}" p.x p.y

let () = main ()

To run the program, save it as string_formatting.ml and use ocamlc to compile and run:

$ ocamlc -o string_formatting string_formatting.ml
$ ./string_formatting
record1: {1 2}
record2: { x: 1; y: 2 }
record3: { x = 1; y = 2 }
type: <obj>
bool: true
int: 123
bin: 00000000000000000000000000001110
char: !
hex: 1c8
float1: 78.900000
float2: 1.234000e+08
float3: 1.234000E+08
str1: "string"
str2: "\"string\""
str3: 6865782074686973
pointer: 140724199169024
width1: |    12|   345|
width2: |  1.20|  3.45|
width3: |1.20  |3.45  |
width4: |   foo|     b|
width5: |foo   |b     |
sprintf: a string
io: an error

Note that OCaml’s string formatting capabilities are similar to those in other languages, but there are some differences. For example, OCaml uses %B for boolean formatting instead of %t, and it doesn’t have a direct equivalent for Go’s %q format specifier for quoting strings. The %a specifier in OCaml is used for custom pretty-printing functions, which can be useful for more complex types.

OCaml’s standard library provides powerful string formatting capabilities through the Printf module, which is similar to the fmt package in Go. However, the exact behavior and available format specifiers may differ slightly between the two languages.