Properly indenting with Format while not knowing when the nested content ends

Viewed 51

I have some functions that call other functions and I want to print the nested calls to see what's happening.

Let's take this minimum example:

let a x = x + 1
let b x = x + 1

let f x =
  let res_a1 = a x in
  let res_b = b x in
  let res_a2 = a x in
  res_a1 + res_b + res_a2

let () = ignore (f 1)

To print what's happening I wrote the following:

let a x =
  Format.printf "a@,";
  x + 1

let b x =
  Format.printf "b@,";
  x + 1

let f x =
  Format.printf "@[<v 2>[f@,";
  let res_a1 = a x in
  let res_b = b x in
  let res_a2 = a x in
  Format.printf "@]@,]@,";
  res_a1 + res_b + res_a2

let () =
  Format.printf "@[<v 0>";
  ignore (f 1);
  Format.printf "@."

The issue it that I have an extra break that I needed to add to have the closing ] properly indented (in my real case I don't know when a nested call is the last call so I can't just not print the @, in the last call):

[f
  a
  b
  a
  
]

If I instead write Format.printf "@]]@,"; then I won't have the extra break but the closing ] will not be properly indented:

[f
  a
  b
  a
  ]

Is there a way to tell Format to properly indent ] without adding an extra break?

Namely, I'd like to have:

[f
  a
  b
  a
]
1 Answers

This is an example of a common problem when you need to print a list of objects interspersed by a separator. If you add a separator after each element you will have an ugly trailing separator. In case the separator is a newline itself, it will also mess with your indentation.

The common solution is to give special treatment to the last element, which doesn't work in your case. However, in your case, it is totally fine to add a separator before each element.

let a x =
  Format.printf "@,a";
  x + 1

let b x =
  Format.printf "@,b";
  x + 1

let f x =
  Format.printf "[@[<v2>f";
  let res_a1 = a x in
  let res_b = b x in
  let res_a2 = a x in
  Format.printf "@]@,]";
  res_a1 + res_b + res_a2

let () =
  Format.printf "@.";
  Format.printf "@[<v0>";
  ignore (f 1);
  Format.printf "@]@."

which gives us proper,

[f
   a
   b
   a
]

Note, that the underlying reason why your code was giving an improper indentation is that you were issuing a break inside of the v2 box in the last call, so it will be always indented with +2.

Related