Skip to content
Deprecated, use ppx_custom_printf instead
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Type Name Latest commit message Commit time
Failed to load latest commit information.


This library defines a syntax extension that allows the use of
user-defined string conversion functions in format strings (that is,
strings passed to printf, sprintf, etc.).

Basic Usage

The basic usage is as follows:

    printf !"The time is %{Time} and the timezone is %{Time.Zone}." time zone

will be transformed by the preprocessor into:

    printf "The time is %s and the timezone is %s."
      (Time.to_string time) (Time.Zone.to_string zone)

In general, specifiers like "%{<Module-path>}" are transformed to "%s",
and [Module-path.to_string] is applied to the appropriate argument.
The module path can even be empty, in which case the generated code calls

Note that you have to prepend the format string with a '!', so that
the preprocessor knows to operate on it.


The syntax "%{sexp:<type>}" is also supported.  For example:

    printf !"The time is %{sexp:Time.t}." time

is transformed to:

    printf "The time is %s."
      (Sexplib.Sexp.to_string_hum (<:sexp_of< Time.t >> time)))

This supports arbritrary type expressions.

You can use [Sexplib.Sexp.to_string_mach] instead of
[Sexplib.Sexp.to_string_hum] by using "%{sexp#mach:<type>}"

Things like:

    ksprintf f !"Time time is %{Time}" time

work as expected.  In general, it doesn't matter where the format
string occurs in the argument list, although the preprocessor does
assume that the arguments following the format string correspond to
the specifiers of the format string.
Partial application

Partial application is supported.  For example:

   printf !"The time is %{Time}"

is essentially transformed to:

  (fun x -> printf "The time is %s" (Time.to_string x))

Actually, it's transformed to something like:

  let y = printf in (fun x -> y "The time is %s" (Time.to_string x))

The reason is to preserve behavior of any side effects.  For example:

   (side_effect (); printf) !"The time is %{Time}"

is transformed to:

  let y = (side_effect (); printf) in
  (fun x -> y "The time is %s" (Time.to_string x))

so that [side_effect ()] is run immediately, just as it would be with
a regular format specifier.
Using functions other than [M.to_string]

The format specifier "%{<Module-path>.<lowercase_identifier>}" corresponds
to that function.  So, for example:

    printf !"The date is %{Core.Std.Date.iso8601_basic}" date

is transformed to:

    printf "The date is %s" (Core.Std.Date.iso8601_basic date)

Further, the format specifier
"%{<Module-path>#<lowercase_identifier>}" corresponds to the function
[<Module_path>.to_string_<lowercase_identifier>].  So, for example:

    printf !"The date is %{Core.Std.Date#hum}" date

is transformed to:
    printf "The date is %s" (Core.Std.Date.to_string_hum date)

Subformats disallowed

In a regular format string, you can use format specifiers of the form
"%{<spec>%}" and "%(<spec>%)" where <spec> is another format

Using these specifiers is disallowed in format strings that are
processed with custom-printf.
You can’t perform that action at this time.