## printf-combinator.api
# Compiled by:
#
src/lib/std/standard.lib# Well-typed "printf" for Mythryl, aka "Unparsing Combinators".
# This code was written by Matthias Blume (2002). Inspiration
# obtained from Olivier Danvy's "Functional Prettyprinting" work.
#
# Description:
#
# The idea is to use combinators to construct something akin to
# the format string of C's printf function. The difference is, however,
# that our formats aren't strings. Instead, format (fragments) have
# meaningful types, and passing them to function "format" 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 %-specifications of printf.)
#
# Here is how the typing works: There is an underlying notion of
# "abstract formats" of type Format(X). However, the user operates
# at the level of "format fragments" which have type
# Fragment(X, Y) and are typically typeagnostic in X (where Y is
# macro expanded to some type containing X). Fragments are
# functions from formats to formats and can be composed freely using
# the function composition operator 'o'. This form of format
# composition translates to a corresponding concatenation of the
# resulting output.
#
# Fragments are composed from two kinds 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). As "glue" we refer
# to 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.
#
# A number of elements and some glue have been predefined.
#
# Here are examples on how to use this facility:
#
# include package printf_combinator;
#
# format nothing ==> ""
#
# format int ==> fn: Int -> String
# format int 1234 ==> "1234"
#
# format (text "The square of " o int o text " is " o int o text ".")
# ==> fn: int -> int -> String
# format (text "The square of " o int o t" is " o int o t".") 2 4
# ==> "The square of 2 is 4."
#
# format (int o bool o char) ==> fn: Int -> Bool -> char -> String
# 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"
#
# Fragments can be padded, trimmed, or fitted to generate text pieces of
# specified sizes. Padding/trimming/fitting may be nested.
# The operations are parameterized by a place (left, center, right) and
# a width. Padding never shrinks strings, trimming never extends
# strings, and fitting is done as necessary by either padding or trimming.
# Examples:
#
# 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"
#
# Nesting:
#
# format (pad right 20 (int o pad left 10 float) o text "x") 12 22.3
# ==> "12 22.3 x"
api Printf_Combinator {
# We reveal "fragments" to be functions from abstract formats
# to abstract formats. This is to make sure we can use function
# composition on them.
Format(X);
Fragment (X, Y)
=
Format(X) -> Format(Y);
# Two primitive kinds of fragments: Glue inserts some text
# into the output without consuming an argument. Elements
# insert text corresponding to some (curried) argument into
# the output:
Glue(X) = Fragment (X, X);
Element(X, T) = Fragment (X, T -> X);
# Format execution
# 1. Simple version, produce final result as a string:
#
format: Fragment (String, X) -> X;
# 2. Complex version, take a receiver function that will
# be invoked with the final result. The result is
# still in non-concatenated form at this time.
# (Internally, the combinators avoid string concatenation
# as long as there is no padding/trimming/fitting going on.)
#
format' : (List( String ) -> Y)
->
Fragment( Y, X )
->
X;
# Make a type-specific element given a
# to_string function for this type:
#
using: (T -> String) -> Element (X, T);
# Macro expand 'using' for a few types...
#
int: Element( X, Int ); # using int::to_string
float: Element( X, Float ); # using eight_byte_float::to_string
bool: Element( X, Bool ); # using bool::to_string
string: Element( X, String ); # using (fn x => x)
string' : Element( X, String ); # using string::to_string
char: Element( X, Char ); # using string::from_char
char' : Element( X, Char ); # using char::to_string
# number_string is from
src/lib/std/src/number-string.pkg # Parameterized elements:
#
int' : number_string::Radix -> Element( X, Int ); # using (int::format r)
float' : number_string::Float_Format -> Element (X, Float); # using (eight_byte_float::format f)
# Generic "gluifier":
#
glue: Element (X, T) -> T -> Glue(X);
# More glue:
#
nothing: Glue(X); # null glue
text: String -> Glue(X); # Constant text glue
sp: Int -> Glue(X); # n spaces glue
nl: Glue(X); # newline glue
tab: Glue(X); # tabulator glue
# "Places" tell which side
# of a string to pad or trim:
#
Place;
left: Place;
center: Place;
right: Place;
# Pad, trim, or fit to size n
# the output corresponding to
# a format fragment:
#
pad: Place -> Int -> Fragment( X, T ) -> Fragment( X, T );
trim: Place -> Int -> Fragment( X, T ) -> Fragment( X, T );
fit: Place -> Int -> Fragment( X, T ) -> Fragment( X, T );
# Specialized padding (left and right)
padl: Int -> Fragment( X, T ) -> Fragment( X, T );
padr: Int -> Fragment( X, T ) -> Fragment( X, T );
};
## COPYRIGHT (c) 2002 Bell Labs, Lucent Technologies
## Subsequent changes by Jeff Prothero Copyright (c) 2010-2015,
## released per terms of SMLNJ-COPYRIGHT.