CamlinternalFormatBasics(3)

๐Ÿ’– CamlinternalFormatBasics(3) ๐Ÿ’–

okay so this is the OCaml library page for CamlinternalFormatBasics(3), and it's part 1, bestie. It's giving internal format basics, and the page is basically a giant stack of types. No cap, every single one is below. โœจ

๐ŸŒธ NAME ๐ŸŒธ

CamlinternalFormatBasics โ€” no description. That's literally it. The manpage said "no description" and I'm not gonna invent lore. ๐Ÿ˜ญ

๐Ÿ“ฆ Module ๐Ÿ“ฆ

Module CamlinternalFormatBasics

โœจ Documentation โœจ

Module CamlinternalFormatBasics

: sig end


Alright, vibe check: here come the types. I'm keeping all the constructors, all the GADT signatures, all the type variables, and all the details, periodt. ๐Ÿ’…

type padty

type padty =
 | Left
 | Right
 | Zeros

type int_conv

type int_conv =
 | Int_d
 | Int_pd
 | Int_sd
 | Int_i
 | Int_pi
 | Int_si
 | Int_x
 | Int_Cx
 | Int_X
 | Int_CX
 | Int_o
 | Int_Co
 | Int_u
 | Int_Cd
 | Int_Ci
 | Int_Cu

type float_flag_conv

type float_flag_conv =
 | Float_flag_
 | Float_flag_p
 | Float_flag_s

type float_kind_conv

type float_kind_conv =
 | Float_f
 | Float_e
 | Float_E
 | Float_g
 | Float_G
 | Float_F
 | Float_h
 | Float_H
 | Float_CF

type float_conv

type float_conv = float_flag_conv * float_kind_conv

type char_set

type char_set = string

type counter

type counter =
 | Line_counter
 | Char_counter
 | Token_counter

type ('a, 'b) padding

type ('a, 'b) padding =
 | No_padding : ('a0, 'a0) padding
 | Lit_padding : padty * int -> ('a1, 'a1) padding
 | Arg_padding : padty -> (int -> 'a2, 'a2) padding

type pad_option

type pad_option = int option

type ('a, 'b) precision

type ('a, 'b) precision =
 | No_precision : ('a0, 'a0) precision
 | Lit_precision : int -> ('a1, 'a1) precision
 | Arg_precision : (int -> 'a2, 'a2) precision

type prec_option

type prec_option = int option

type ('a, 'b, 'c) custom_arity

type ('a, 'b, 'c) custom_arity =
 | Custom_zero : ('a0, string, 'a0) custom_arity
 | Custom_succ : ('a1, 'b0, 'c0) custom_arity -> ('a1, 'x -> 'b0, 'x ->
'c0) custom_arity

type block_type

type block_type =
 | Pp_hbox
 | Pp_vbox
 | Pp_hvbox
 | Pp_hovbox
 | Pp_box
 | Pp_fits

type formatting_lit

type formatting_lit =
 | Close_box
 | Close_tag
 | Break of string * int * int
 | FFlush
 | Force_newline
 | Flush_newline
 | Magic_size of string * int
 | Escaped_at
 | Escaped_percent
 | Scan_indic of char

type ('a, 'b, 'c, 'd, 'e, 'f) formatting_gen

type ('a, 'b, 'c, 'd, 'e, 'f) formatting_gen =
 | Open_tag : ('a0, 'b0, 'c0, 'd0, 'e0, 'f0) format6 -> ('a0, 'b0, 'c0,
'd0, 'e0, 'f0) formatting_gen
 | Open_box : ('a1, 'b1, 'c1, 'd1, 'e1, 'f1) format6 -> ('a1, 'b1, 'c1,
'd1, 'e1, 'f1) formatting_gen

type ('a, 'b, 'c, 'd, 'e, 'f) fmtty

type ('a, 'b, 'c, 'd, 'e, 'f) fmtty = ('a, 'b, 'c, 'd, 'e, 'f, 'a, 'b,
'c, 'd, 'e, 'f) fmtty_rel

type ('a1, 'b1, 'c1, 'd1, 'e1, 'f1, 'a2, 'b2, 'c2, 'd2, 'e2, 'f2) fmtty_rel

type ('a1, 'b1, 'c1, 'd1, 'e1, 'f1, 'a2, 'b2, 'c2, 'd2, 'e2, 'f2)
fmtty_rel =
 | Char_ty : ('a10, 'b10, 'c10, 'd10, 'e10, 'f10, 'a20, 'b20, 'c20,
'd20, 'e20, 'f20) fmtty_rel -> (char -> 'a10, 'b10, 'c10, 'd10, 'e10,
'f10, char -> 'a20, 'b20, 'c20, 'd20, 'e20, 'f20) fmtty_rel
 | String_ty : ('a11, 'b11, 'c11, 'd11, 'e11, 'f11, 'a21, 'b21, 'c21,
'd21, 'e21, 'f21) fmtty_rel -> (string -> 'a11, 'b11, 'c11, 'd11, 'e11,
'f11, string -> 'a21, 'b21, 'c21, 'd21, 'e21, 'f21) fmtty_rel
 | Int_ty : ('a12, 'b12, 'c12, 'd12, 'e12, 'f12, 'a22, 'b22, 'c22, 'd22,
'e22, 'f22) fmtty_rel -> (int -> 'a12, 'b12, 'c12, 'd12, 'e12, 'f12, int
-> 'a22, 'b22, 'c22, 'd22, 'e22, 'f22) fmtty_rel
 | Int32_ty : ('a13, 'b13, 'c13, 'd13, 'e13, 'f13, 'a23, 'b23, 'c23,
'd23, 'e23, 'f23) fmtty_rel -> (int32 -> 'a13, 'b13, 'c13, 'd13, 'e13,
'f13, int32 -> 'a23, 'b23, 'c23, 'd23, 'e23, 'f23) fmtty_rel
 | Nativeint_ty : ('a14, 'b14, 'c14, 'd14, 'e14, 'f14, 'a24, 'b24, 'c24,
'd24, 'e24, 'f24) fmtty_rel -> (nativeint -> 'a14, 'b14, 'c14, 'd14,
'e14, 'f14, nativeint -> 'a24, 'b24, 'c24, 'd24, 'e24, 'f24) fmtty_rel
 | Int64_ty : ('a15, 'b15, 'c15, 'd15, 'e15, 'f15, 'a25, 'b25, 'c25,
'd25, 'e25, 'f25) fmtty_rel -> (int64 -> 'a15, 'b15, 'c15, 'd15, 'e15,
'f15, int64 -> 'a25, 'b25, 'c25, 'd25, 'e25, 'f25) fmtty_rel
 | Float_ty : ('a16, 'b16, 'c16, 'd16, 'e16, 'f16, 'a26, 'b26, 'c26,
'd26, 'e26, 'f26) fmtty_rel -> (float -> 'a16, 'b16, 'c16, 'd16, 'e16,
'f16, float -> 'a26, 'b26, 'c26, 'd26, 'e26, 'f26) fmtty_rel
 | Bool_ty : ('a17, 'b17, 'c17, 'd17, 'e17, 'f17, 'a27, 'b27, 'c27,
'd27, 'e27, 'f27) fmtty_rel -> (bool -> 'a17, 'b17, 'c17, 'd17, 'e17,
'f17, bool -> 'a27, 'b27, 'c27, 'd27, 'e27, 'f27) fmtty_rel
 | Format_arg_ty : ('g, 'h, 'i, 'j, 'k, 'l) fmtty * ('a18, 'b18, 'c18,
'd18, 'e18, 'f18, 'a28, 'b28, 'c28, 'd28, 'e28, 'f28) fmtty_rel -> (('g,
'h, 'i, 'j, 'k, 'l) format6 -> 'a18, 'b18, 'c18, 'd18, 'e18, 'f18, ('g,
'h, 'i, 'j, 'k, 'l) format6 -> 'a28, 'b28, 'c28, 'd28, 'e28, 'f28)
fmtty_rel
 | Format_subst_ty : ('g0, 'h0, 'i0, 'j0, 'k0, 'l0, 'g1, 'b19, 'c19,
'j1, 'd19, 'a19) fmtty_rel * ('g0, 'h0, 'i0, 'j0, 'k0, 'l0, 'g2, 'b29,
'c29, 'j2, 'd29, 'a29) fmtty_rel * ('a19, 'b19, 'c19, 'd19, 'e19, 'f19,
'a29, 'b29, 'c29, 'd29, 'e29, 'f29) fmtty_rel -> (('g0, 'h0, 'i0, 'j0,
'k0, 'l0) format6 -> 'g1, 'b19, 'c19, 'j1, 'e19, 'f19, ('g0, 'h0, 'i0,
'j0, 'k0, 'l0) format6 -> 'g2, 'b29, 'c29, 'j2, 'e29, 'f29) fmtty_rel
 | Alpha_ty : ('a110, 'b110, 'c110, 'd110, 'e110, 'f110, 'a210, 'b210,
'c210, 'd210, 'e210, 'f210) fmtty_rel -> (('b110 -> 'x -> 'c110) -> 'x
-> 'a110, 'b110, 'c110, 'd110, 'e110, 'f110, ('b210 -> 'x -> 'c210) ->
'x -> 'a210, 'b210, 'c210, 'd210, 'e210, 'f210) fmtty_rel
 | Theta_ty : ('a111, 'b111, 'c111, 'd111, 'e111, 'f111, 'a211, 'b211,
'c211, 'd211, 'e211, 'f211) fmtty_rel -> (('b111 -> 'c111) -> 'a111,
'b111, 'c111, 'd111, 'e111, 'f111, ('b211 -> 'c211) -> 'a211, 'b211,
'c211, 'd211, 'e211, 'f211) fmtty_rel
 | Any_ty : ('a112, 'b112, 'c112, 'd112, 'e112, 'f112, 'a212, 'b212,
'c212, 'd212, 'e212, 'f212) fmtty_rel -> ('x0 -> 'a112, 'b112, 'c112,
'd112, 'e112, 'f112, 'x0 -> 'a212, 'b212, 'c212, 'd212, 'e212, 'f212)
fmtty_rel
 | Reader_ty : ('a113, 'b113, 'c113, 'd113, 'e113, 'f113, 'a213, 'b213,
'c213, 'd213, 'e213, 'f213) fmtty_rel -> ('x1 -> 'a113, 'b113, 'c113,
('b113 -> 'x1) -> 'd113, 'e113, 'f113, 'x1 -> 'a213, 'b213, 'c213,
('b213 -> 'x1) -> 'd213, 'e213, 'f213) fmtty_rel
 | Ignored_reader_ty : ('a114, 'b114, 'c114, 'd114, 'e114, 'f114, 'a214,
'b214, 'c214, 'd214, 'e214, 'f214) fmtty_rel -> ('a114, 'b114, 'c114,
('b114 -> 'x2) -> 'd114, 'e114, 'f114, 'a214, 'b214, 'c214, ('b214 ->
'x2) -> 'd214, 'e214, 'f214) fmtty_rel
 | End_of_fmtty : ('f115, 'b115, 'c115, 'd115, 'd115, 'f115, 'f215,
'b215, 'c215, 'd215, 'd215, 'f215) fmtty_rel

type ('a, 'b, 'c, 'd, 'e, 'f) fmt

type ('a, 'b, 'c, 'd, 'e, 'f) fmt =
 | Char : ('a0, 'b0, 'c0, 'd0, 'e0, 'f0) fmt -> (char -> 'a0, 'b0, 'c0,
'd0, 'e0, 'f0) fmt
 | Caml_char : ('a1, 'b1, 'c1, 'd1, 'e1, 'f1) fmt -> (char -> 'a1, 'b1,
'c1, 'd1, 'e1, 'f1) fmt
 | String : ('x, string -> 'a2) padding * ('a2, 'b2, 'c2, 'd2, 'e2, 'f2)
fmt -> ('x, 'b2, 'c2, 'd2, 'e2, 'f2) fmt
 | Caml_string : ('x0, string -> 'a3) padding * ('a3, 'b3, 'c3, 'd3,
'e3, 'f3) fmt -> ('x0, 'b3, 'c3, 'd3, 'e3, 'f3) fmt
 | Int : int_conv * ('x1, 'y) padding * ('y, int -> 'a4) precision *
('a4, 'b4, 'c4, 'd4, 'e4, 'f4) fmt -> ('x1, 'b4, 'c4, 'd4, 'e4, 'f4) fmt
 | Int32 : int_conv * ('x2, 'y0) padding * ('y0, int32 -> 'a5) precision
* ('a5, 'b5, 'c5, 'd5, 'e5, 'f5) fmt -> ('x2, 'b5, 'c5, 'd5, 'e5, 'f5)
fmt
 | Nativeint : int_conv * ('x3, 'y1) padding * ('y1, nativeint -> 'a6)
precision * ('a6, 'b6, 'c6, 'd6, 'e6, 'f6) fmt -> ('x3, 'b6, 'c6, 'd6,
'e6, 'f6) fmt
 | Int64 : int_conv * ('x4, 'y2) padding * ('y2, int64 -> 'a7) precision
* ('a7, 'b7, 'c7, 'd7, 'e7, 'f7) fmt -> ('x4, 'b7, 'c7, 'd7, 'e7, 'f7)
fmt
 | Float : float_conv * ('x5, 'y3) padding * ('y3, float -> 'a8)
precision * ('a8, 'b8, 'c8, 'd8, 'e8, 'f8) fmt -> ('x5, 'b8, 'c8, 'd8,
'e8, 'f8) fmt
 | Bool : ('x6, bool -> 'a9) padding * ('a9, 'b9, 'c9, 'd9, 'e9, 'f9)
fmt -> ('x6, 'b9, 'c9, 'd9, 'e9, 'f9) fmt
 | Flush : ('a10, 'b10, 'c10, 'd10, 'e10, 'f10) fmt -> ('a10, 'b10,
'c10, 'd10, 'e10, 'f10) fmt
 | String_literal : string * ('a11, 'b11, 'c11, 'd11, 'e11, 'f11) fmt ->
('a11, 'b11, 'c11, 'd11, 'e11, 'f11) fmt
 | Char_literal : char * ('a12, 'b12, 'c12, 'd12, 'e12, 'f12) fmt ->
('a12, 'b12, 'c12, 'd12, 'e12, 'f12) fmt
 | Format_arg : pad_option * ('g, 'h, 'i, 'j, 'k, 'l) fmtty * ('a13,
'b13, 'c13, 'd13, 'e13, 'f13) fmt -> (('g, 'h, 'i, 'j, 'k, 'l) format6
-> 'a13, 'b13, 'c13, 'd13, 'e13, 'f13) fmt
 | Format_subst : pad_option * ('g0, 'h0, 'i0, 'j0, 'k0, 'l0, 'g2, 'b14,
'c14, 'j2, 'd14, 'a14) fmtty_rel * ('a14, 'b14, 'c14, 'd14, 'e14, 'f14)
fmt -> (('g0, 'h0, 'i0, 'j0, 'k0, 'l0) format6 -> 'g2, 'b14, 'c14, 'j2,
'e14, 'f14) fmt
 | Alpha : ('a15, 'b15, 'c15, 'd15, 'e15, 'f15) fmt -> (('b15 -> 'x7 ->
'c15) -> 'x7 -> 'a15, 'b15, 'c15, 'd15, 'e15, 'f15) fmt
 | Theta : ('a16, 'b16, 'c16, 'd16, 'e16, 'f16) fmt -> (('b16 -> 'c16)
-> 'a16, 'b16, 'c16, 'd16, 'e16, 'f16) fmt
 | Formatting_lit : formatting_lit * ('a17, 'b17, 'c17, 'd17, 'e17,
'f17) fmt -> ('a17, 'b17, 'c17, 'd17, 'e17, 'f17) fmt
 | Formatting_gen : ('a18, 'b18, 'c18, 'd18, 'e18, 'f18) formatting_gen
* ('f18, 'b18, 'c18, 'e18, 'e20, 'f20) fmt -> ('a18, 'b18, 'c18, 'd18,
'e20, 'f20) fmt
 | Reader : ('a19, 'b19, 'c19, 'd19, 'e19, 'f19) fmt -> ('x8 -> 'a19,
'b19, 'c19, ('b19 -> 'x8) -> 'd19, 'e19, 'f19) fmt
 | Scan_char_set : pad_option * char_set * ('a20, 'b20, 'c20, 'd20,
'e21, 'f21) fmt -> (string -> 'a20, 'b20, 'c20, 'd20, 'e21, 'f21) fmt
 | Scan_get_counter : counter * ('a21, 'b21, 'c21, 'd21, 'e22, 'f22) fmt
-> (int -> 'a21, 'b21, 'c21, 'd21, 'e22, 'f22) fmt
 | Scan_next_char : ('a22, 'b22, 'c22, 'd22, 'e23, 'f23) fmt -> (char ->
'a22, 'b22, 'c22, 'd22, 'e23, 'f23) fmt
 | Ignored_param : ('a23, 'b23, 'c23, 'd23, 'y4, 'x9) ignored * ('x9,
'b23, 'c23, 'y4, 'e24, 'f24) fmt -> ('a23, 'b23, 'c23, 'd23, 'e24, 'f24)
fmt
 | Custom : ('a24, 'x10, 'y5) custom_arity * (unit -> 'x10) * ('a24,
'b24, 'c24, 'd24, 'e25, 'f25) fmt -> ('y5, 'b24, 'c24, 'd24, 'e25, 'f25)
fmt
 | End_of_format : ('f26, 'b25, 'c25, 'e26, 'e26, 'f26) fmt

And then the page just says, fr fr:

List of format elements.

okay bestie, we're still deep in the Documentation section and the types are about to get spicy ๐Ÿ”ฅ โ€” don't worry, I'm keeping every single type variable exactly where it belongs, no cap.


๐Ÿ’… the ignored type โ€” the "everything we saw but don't return" club

This is a GADT, which is just a fancy way of saying each constructor carries its own types. Every variant here describes something the format machinery noticed but doesn't hand back to you as a result. The constructor list, verbatim, no edits, no vibes-based renaming:

type ('a, 'b, 'c, 'd, 'e, 'f) ignored =
  | Ignored_char : ('a0, 'b0, 'c0, 'd0, 'd0, 'a0) ignored
  | Ignored_caml_char : ('a1, 'b1, 'c1, 'd1, 'd1, 'a1) ignored
  | Ignored_string : pad_option -> ('a2, 'b2, 'c2, 'd2, 'd2, 'a2) ignored
  | Ignored_caml_string : pad_option -> ('a3, 'b3, 'c3, 'd3, 'd3, 'a3) ignored
  | Ignored_int : int_conv * pad_option -> ('a4, 'b4, 'c4, 'd4, 'd4, 'a4) ignored
  | Ignored_int32 : int_conv * pad_option -> ('a5, 'b5, 'c5, 'd5, 'd5, 'a5) ignored
  | Ignored_nativeint : int_conv * pad_option -> ('a6, 'b6, 'c6, 'd6, 'd6, 'a6) ignored
  | Ignored_int64 : int_conv * pad_option -> ('a7, 'b7, 'c7, 'd7, 'd7, 'a7) ignored
  | Ignored_float : pad_option * prec_option -> ('a8, 'b8, 'c8, 'd8, 'd8, 'a8) ignored
  | Ignored_bool : pad_option -> ('a9, 'b9, 'c9, 'd9, 'd9, 'a9) ignored
  | Ignored_format_arg : pad_option * ('g, 'h, 'i, 'j, 'k, 'l) fmtty ->
      ('a10, 'b10, 'c10, 'd10, 'd10, 'a10) ignored
  | Ignored_format_subst : pad_option * ('a11, 'b11, 'c11, 'd11, 'e0, 'f0) fmtty ->
      ('a11, 'b11, 'c11, 'd11, 'e0, 'f0) ignored
  | Ignored_reader : ('a12, 'b12, 'c12, ('b12 -> 'x) -> 'd12, 'd12, 'a12) ignored
  | Ignored_scan_char_set : pad_option * char_set -> ('a13, 'b13, 'c13, 'd13, 'd13, 'a13) ignored
  | Ignored_scan_get_counter : counter -> ('a14, 'b14, 'c14, 'd14, 'd14, 'a14) ignored
  | Ignored_scan_next_char : ('a15, 'b15, 'c15, 'd15, 'd15, 'a15) ignored

like, look at all those numbered type variables โ€” 'a0 through 'a15, bestie really said "I will not be sharing." ๐Ÿ’€ The way each constructor has its own little payload (pad_option, int_conv, prec_option, char_set, counter, fmtty, โ€ฆ) is honestly iconic. And no, I did not merge any of them, don't even try me ๐Ÿ™ˆ


๐ŸŽ€ format6 โ€” the actual format, starring a string

type ('a, 'b, 'c, 'd, 'e, 'f) format6 =
  | Format of ('a, 'b, 'c, 'd, 'e, 'f) fmt * string

one constructor, Format, holding a fmt and a string. that's it. that's the whole type. simple, clean, ate. โœจ


๐Ÿฆ‹ concat_fmtty โ€” gluing two fmtty_rels together

val concat_fmtty :
  ('g1, 'b1, 'c1, 'j1, 'd1, 'a1, 'g2, 'b2, 'c2, 'j2, 'd2, 'a2) fmtty_rel ->
  ('a1, 'b1, 'c1, 'd1, 'e1, 'f1, 'a2, 'b2, 'c2, 'd2, 'e2, 'f2) fmtty_rel ->
  ('g1, 'b1, 'c1, 'j1, 'e1, 'f1, 'g2, 'b2, 'c2, 'j2, 'e2, 'f2) fmtty_rel

twelve type parameters per argument, and the result also has twelve. yes, twelve. I counted. twice. ๐Ÿงฎ the type signature is doing the absolute most and we respect it.


๐ŸŒธ erase_rel โ€” bye-bye relational info

val erase_rel :
  ('a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, 'i, 'j, 'k, 'l) fmtty_rel ->
  ('a, 'b, 'c, 'd, 'e, 'f) fmtty

takes a fmtty_rel with twelve params, gives you back a plain fmtty with six. the relational extra bits? gone. not invited to the afterparty. ๐Ÿ’…


๐Ÿ’œ concat_fmt โ€” two fmts walk into a bar

val concat_fmt :
  ('a, 'b, 'c, 'd, 'e, 'f) fmt ->
  ('f, 'b, 'c, 'e, 'g, 'h) fmt ->
  ('a, 'b, 'c, 'd, 'g, 'h) fmt

notice how the first argument's 'f slides right into the second argument's first slot? that's the whole bit. it's giving puzzle piece energy. ๐Ÿงฉ


โญ neutral_concat โ€” a record with one very extra field

type neutral_concat = {
  f : 'a 'b 'c 'd 'e 'f.
    [ `Char of char | `String of string ] ->
    ('a, 'b, 'c, 'd, 'e, 'f) fmt ->
    ('a, 'b, 'c, 'd, 'e, 'f) fmt ;
}

okay so this is a record with exactly one field, f, and f is polymorphic over 'a 'b 'c 'd 'e 'f. โ€” yes, that dot is doing real work, it's a polymorphic field, don't touch it. the field takes a polymorphic variant that's either `Char of char or `String of string, plus an fmt, and returns an fmt with the same six params. and yes, that ; with the space before the semicolon is exactly how it's written. i don't make the rules. ๐Ÿซถ


๐Ÿ“ string_concat_map โ€” the actual helper

val string_concat_map :
  neutral_concat -> ('a, 'b, 'c, 'd, 'e, 'f) fmt -> ('a, 'b, 'c, 'd, 'e, 'f) fmt

takes a neutral_concat, takes an fmt, gives you back an fmt with the same six params. no notes. ๐Ÿ‘‘

and the doc text, word for word:

Helper function for splitting format string and char literal.

Since 5.4 โ€” so this one's been serving looks since version 5.4, we love a seasoned icon. ๐ŸŒˆ


aaaaand that's a wrap on part 2, bestie ๐Ÿ’– you made it through all fifteen Ignored_* constructors, twelve-param type signatures, and one wildly polite polymorphic record field. go drink some water ๐Ÿงš

page brought to you by OCamldoc, dated 2026-06-22, for CamlinternalFormatBasics(3) โ€” mwah, stay hydrated, and remember: type variables are load-bearing ๐Ÿ’…โœจ

๐Ÿ“ฆ where this page comes from
  • arch rolling: ocaml 5.5.0-1 ยท LGPL2.1 AND custom: QPL-1.0
  • ๐Ÿ’– girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms