The FormatComb
structure provides well-typed formating (or unparsing)
combinators in the style of Olivier Danvy’s
Functional Unparsing work.
The idea is to use combinators for constructing something akin to
the format string of C's printf
function. The difference is, however,
that our formats are not strings. Instead, format fragments have
meaningful types, and passing them to the format
function results
in a curried function whose arguments have precisely the types that
correspond to argument-consuming parts of the format. (Such
argument-consuming parts are similar to the conversion-specifications
the Format
structure.)
There is an underlying notion of "abstract formats" of type 'a format
,
but the user operates at the level of "format fragments," which
have type ('a, 'b) fragment
and are typically polymorphic
in 'a
(where 'b
is instantiated to some type containing 'a
).
Fragments are functions from formats to formats and can be composed
freely using the infix function-composition operator (o
). This
form of format composition translates to a corresponding concatenation
of the resulting output.
Fragments are composed from two kids of primitve fragments called elements and glue, respectively. An element is a fragment that consumes some argument (which thanks to the typing magic appears as a curried argument when the format gets executed). Glue are fragments that do not consume arguments but merely insert fixed text (fixed at format construction time) into the output.
There are also adjustment operations that pad, trim, or fit the output of entire fragments (primitive or not) to a given size.
Matthias Blume wrote the code for this module.
Synopsis
signature FORMAT_COMB
structure FormatComb : FORMAT_COMB
Interface
type 'a format
type ('a, 'b) fragment = 'a format -> 'b format
type 'a glue = ('a, 'a) fragment
type ('a, 't) element = ('a, 't -> 'a) fragment
type 'a gg
val format : (string, 'a) fragment -> 'a
val format' : (string list -> 'b) -> ('b, 'a) fragment -> 'a
val using : ('t -> string) -> ('a, 't) element
val int : ('a, int) element
val real : ('a, real) element
val bool : ('a, bool) element
val string : ('a, string) element
val string' : ('a, string) element
val char : ('a, char) element
val char' : ('a, char) element
val int' : StringCvt.radix -> ('a, int) element
val real' : StringCvt.realfmt -> ('a, real) element
val list : ('a, 'x) element -> ('a, 'x list) element
val option : ('a, 'x) element -> ('a, 'x option) element
val seq : (('x * 'a gg -> 'a gg) -> 'a gg -> 's -> 'a gg)
-> 'a glue
-> ('a, 'x) element
-> ('a, 's) element
val glue : ('a, 't) element -> 't -> 'a glue
val elem : ('t -> 'a glue) -> ('a, 't) element
val nothing : 'a glue
val text : string -> 'a glue
val sp : int -> 'a glue
val nl : 'a glue
val tab : 'a glue
val listg : ('t -> 'a glue) -> ('t list -> 'a glue)
val optiong : ('t -> 'a glue) -> ('t option -> 'a glue)
val seqg : (('x * 'a gg -> 'a gg) -> 'a gg -> 's -> 'a gg)
-> 'a glue
-> ('x -> 'a glue)
-> 's -> 'a glue
type place
val left : place
val center : place
val right : place
val pad : place -> int -> ('a, 't) fragment -> ('a, 't) fragment
val trim : place -> int -> ('a, 't) fragment -> ('a, 't) fragment
val fit : place -> int -> ('a, 't) fragment -> ('a, 't) fragment
val padl : int -> ('a, 't) fragment -> ('a, 't) fragment
val padr : int -> ('a, 't) fragment -> ('a, 't) fragment
Description
type 'a format
-
An abstract type; values of this type are internal to the implementation.
type ('a, 'b) fragment = 'a format -> 'b format
-
A fragment is a function from formats to formats.
type 'a glue = ('a, 'a) fragment
-
A
glue
fragment insertes text into the output without consuming and argument. type ('a, 't) element = ('a, 't -> 'a) fragment
-
An
element
fragment consumes an argument of type't
, converts it to a string, and inserts the result in the output. type 'a gg
-
An abstract helper type that is internal to the implementation.
val format : (string, 'a) fragment -> 'a
-
format fmt
returns a format function as defined by the expressionfmt
that will produce a string result when applied to the necessary arguments. val format' : (string list -> 'b) -> ('b, 'a) fragment -> 'a
-
format' consumer fmt
returns a format function as defined by the expressionfmt
that will invoke theconsumer
on the list of strings produced by formating when applied to the necessary arguments. (The argument to theconsumer
is a string list to avoid premature string concatenation in the implementation). Note that theformat
function can be defined in terms offormat'
as follows:
val format = format' String.concat
(* Make a type-specific element given a toString function for this type *) `[.kw]#val# using : ('t \-> string) \-> ('a, 't) element`:: `using tos` returns an element fragment that represents the given "value-to-string" conversion.
val int : ('a, int) element
-
an element fragment for formating integers; it is equivalent to the expression
using Int.toString
. val int' : StringCvt.radix -> ('a, int) element
-
int' radix
returns an element fragment for formating integers in the specifiedradix
. It is equivalent to the expressionusing (Int.fmt radix)
. val real : ('a, real) element
-
an element fragment for formating reals; it is equivalent to the expression
using Real.toString
. val real' : StringCvt.realfmt -> ('a, real) element
-
real' rf
returns an element fragment for formating reals with the specified format. It is equivalent to the expressionusing (Real.fmt rf)
. val bool : ('a, bool) element
-
an element fragment for formating booleans; it is equivalent to the expression
using Bool.toString
. val string : ('a, string) element
-
an element fragment for formating raw strings; it is equivalent to the expression
using (fn x ⇒ x)
. val string' : ('a, string) element
-
an element fragment for formating strings with escapes; it is equivalent to the expression
using String.toString
. val char : ('a, char) element (* using String.str *)
-
an element fragment for formating raw characters; it is equivalent to the expression
using String.str
. val char' : ('a, char) element (* using Char.toString *)
-
an element fragment for formating characters with escapes; it is equivalent to the expression
using Char.toString
.(* "polymorphic" elements *)
val list : ('a, 'x) element -> ('a, 'x list) element (* "[", ", ", "]" *)
-
list elemFmt
returns an element fragment that formats lists of items using theelemFmt
element fragment to format items. The list will be enclosed in brackets (“`[” “
]`”) with elements separated by commas. val option : ('a, 'x) element -> ('a, 'x option) element
-
option elemFmt
returns an element fragment that formats optional items using theelemFmt
element fragment to format the item value. For an argument ofNONE
, the string"NONE"
is returned, while for an argument ofSOME v
, the string"SOME(s)"
is returned, wheres
is the result of formattingv
usingelemFmt
. val seq : (('x * 'a gg -> 'a gg) -> 'a gg -> 's -> 'a gg) -> 'a glue -> ('a, 'x) element -> ('a, 's) element
-
something
val glue : ('a, 't) element -> 't -> 'a glue
-
glue fmt arg
returns a glue element that renders as the string that results from usingfmt
to convertarg
to a string. val elem : ('t -> 'a glue) -> ('a, 't) element
-
elem glueGen
returns an element for rendering arguments to theglueGen
function. This function is the inverse ofglue
and is useful for extending the set of combinators. val nothing : 'a glue
-
A glue fragment that renders as the empty string.
val text : string -> 'a glue
-
text s
returns a glue fragment that renders as the texts
. val sp : int -> 'a glue
-
sp n
returns a glue fragment that renders asn
space characters. val nl : 'a glue
-
A glue fragment that renders as a newline character.
val tab : 'a glue
-
A glue fragment that renders as a tab character.
val listg : ('t -> 'a glue) -> ('t list -> 'a glue)
-
something
val optiong : ('t -> 'a glue) -> ('t option -> 'a glue)
-
something
val seqg : (('x * 'a gg -> 'a gg) -> 'a gg -> 's -> 'a gg) -> 'a glue -> ('x -> 'a glue) -> 's -> 'a glue
-
something
type place
-
An abstract type that represents how to pad or trim of string.
val left : place
-
Pad or trim the left side of a string.
val center : place
-
Pad or trim both sides of a string.
val right : place
-
Pad or trim the left side of a string.
val pad : place -> int -> ('a, 't) fragment -> ('a, 't) fragment
-
pad place n frag
wraps the fragmentfrag
with padding to bring the total with to no fewer thann
characters. Theplace
specifies where padding spaces will be added. Padding never reduces the size of the result.
val trim : place -> int -> ('a, 't) fragment -> ('a, 't) fragment
-
trim place n frag
wraps the fragmentfrag
with a trimming operation to bring the total with to no more thann
characters. Theplace
specifies where trimming occurs. Trimming never increases the size of the result.
val fit : place -> int -> ('a, 't) fragment -> ('a, 't) fragment
-
fit place n frag
wraps the fragmentfrag
with an operation that guarantees the result will be exactlyn
characters by either padding or trimming as necessary. val padl : int -> ('a, 't) fragment -> ('a, 't) fragment
-
padl n frag
is equivalent topad left n frag
. val padr : int -> ('a, 't) fragment -> ('a, 't) fragment
-
padr n frag
is equivalent topad right n frag
.
Examples
Here are examples on how to use this facility.
format nothing (* ==> "" *)
format int 1234 (* ==> "1234" *)
format (text "The square of " o int o text " is " o int o text ".") 2 4
(* ==> "The square of 2 is 4." *)
format (int o bool o char) 1 true #"x"
(* ==> "1truex" *)
format (glue string "glue vs. " o string o glue int 42 o sp 5 o int)
"ordinary text " 17
(* ==> "glue vs. ordinary text 42 17" *)
format (pad left 6 int) 1234 (* ==> " 1234" *)
format (pad center 6 int) 1234 (* ==> " 1234 " *)
format (pad right 6 int) 1234 (* ==> "1234 " *)
format (trim left 2 int) 1234 (* ==> "34" *)
format (trim center 2 int) 1234 (* ==> "23" *)
format (trim right 2 int) 1234 (* ==> "12" *)
format (fit left 3 int) 12 (* ==> " 12" *)
format (fit left 3 int) 123 (* ==> "123" *)
format (fit left 3 int) 1234 (* ==> "234" *)