6 Formlets: Functional Form Abstraction
The Web Server provides a kind of Web form abstraction called a formlet.
Formlets originate in the work of the Links research group in
their paper The Essence of Form Abstraction.
6.1 Basic Formlet Usage
Suppose we want to create an abstraction of entering a date in an HTML form. The following
formlet captures this idea:
The first part of the formlet syntax is the template of an X-expression that is the rendering
of the formlet. It can contain elements like ,(=> formlet name) where formlet
is a formlet expression and name is an identifier bound in the second part of the formlet
syntax.
This formlet is displayed (with formlet-display) as the following X-expression forest (list):
| (list | 
| '(div "Month:" (input ([name "input_0"])) | 
| "Day:" (input ([name "input_1"])))) | 
date-formlet not only captures the rendering of the form, but also the request processing
logic. If we send it an HTTP request with bindings for "input_0" to "10" and
"input_1" to "3", with formlet-process, then it returns:
(list 10 3)
which is the second part of the formlet syntax, where month has been replaced with the
integer represented by the "input_0" and day has been replaced with the
integer represented by the "input_1".
The real power of formlet is that they can be embedded within one another. For instance, suppose we want to
combine two date forms to capture a travel itinerary. The following formlet does the job:
| (define travel-formlet | 
| (formlet | 
| (div | 
| "Name:" ,{input-string . => . name} | 
| (div | 
| "Arrive:" ,{date-formlet . => . arrive} | 
| "Depart:" ,{date-formlet . => . depart}) | 
| (list name arrive depart)))) | 
(Notice that date-formlet is embedded twice.) This is rendered as:
| (list | 
| '(div | 
| "Name:" | 
| (input ([name "input_0"])) | 
| (div | 
| "Arrive:" | 
| (div "Month:" (input ([name "input_1"])) | 
| "Day:" (input ([name "input_2"]))) | 
| "Depart:" | 
| (div "Month:" (input ([name "input_3"])) | 
| "Day:" (input ([name "input_4"])))))) | 
Observe that formlet-display has automatically generated unique names for each input element. When we pass
bindings for these names to formlet-process, the following list is returned:
In all these examples, we used the input-int and
input-string formlets. Any value with the formlet
contract can be used in these positions. For example,
(to-string (required (text-input))) could be used as
well. The rest of the manual gives the details of formlet
usage, extension, and existing formlet combinators.
6.2 Static Syntactic Shorthand
Most users will want to use the syntactic shorthand for creating 
formlets.
| (formlet rendering-xexpr yields-expr)
 | 
Constructs a 
formlet with the specified 
rendering-xexpr and the processing
result is the evaluation of the 
yields-expr expression. The 
rendering-xexpr form is a quasiquoted
syntactic 
X-expression, with three special caveats:
,{=> formlet-expr name} embeds the
formlet given by 
formlet-expr; the result of processing this formlet is
available in the 
yields-expr as 
name.
 ,{=> formlet-expr (values name ...)} embeds the
formlet given by 
formlet-expr; the results of processing this formlet is
available in the 
yields-expr as 
name ....
 6.3 Dynamic Syntactic Shorthand
The 
formlet syntax is too restrictive for some applications because it forces the 
rendering
to be 
syntactically an 
X-expression. You may discover you want to use a more "dynamic" shorthand.
Constructs a 
formlet where 
rendering-expr is evaluated (with caveats) to construct the rendering
and the processing result is the evaluation of the 
yields-expr expression.
The 
rendering-expr should evaluate to an "
X-expression" that may embed the results of the following forms
that only have meaning within 
formlet*:
{=>* formlet-expr name} embeds the
formlet given by 
formlet-expr; the result of processing this formlet is
available in the 
yields-expr as 
name.
 {=>* formlet-expr (values name ...)} embeds the
formlet given by 
formlet-expr; the results of processing this formlet is
available in the 
yields-expr as 
name ....
 Each of these forms evaluates to an opaque value that 
rendering-expr may not manipulate in any way,
but if it is returned to 
formlet* as part of an "
X-expression" it will be rendered and the formlets processing
stages will be executed, etc.
Because these forms 
may appear anywhere in 
rendering-expr, they may be duplicated. Therefore,
the formlet may render (and be processed) multiple times. Thus, in 
yields-expr the formlet result names are
bound to lists of results rather than single results as in 
formlet. The result list is ordered according
to the order of the formlets in the result of 
rendering-expr. For example, in
name is bound to a list of strings, not a single string, where the first element is the string that
was inputted next to the string 1 on the Web page.
In this example, it is clear that this is the desired behavior. However, sometimes the value of a formlet’s
result may be surprising. For example, in
name is bound to a list of strings, because 
formlet* cannot syntactically determine if
the formlet whose result is bound to 
name is used many times.
 6.4 Functional Usage
The syntactic shorthand abbreviates the construction of 
formlets with the following library.
These combinators may be used directly to construct low-level formlets, such as those for new INPUT element
types. Refer to 
Predefined Formlets for example low-level formlets using these combinators.
A 
formlet’s internal representation is a function from an initial input number
to an 
X-expression forest rendering, a processing function, and the next allowable
input number.
Constructs a 
formlet that has no rendering and always returns 
value in
the processing stage.
Constructs a 
formlet with a rendering equal to the concatenation of the renderings of 
formlets 
f and 
g;
a processing stage that applies 
g’s processing results to 
f’s processing result.
Equivalent to 
cross lifted to many arguments.
Constructs a 
formlet with the rendering 
r and the
identity procedure as the processing step.
Constructs a 
formlet with the rendering 
(list (list* tag attrs inner-rendering)) where 
inner-rendering is the
rendering of 
inner and the processing stage identical to
inner.
Runs the processing stage of f on the bindings in r.
6.5 Predefined Formlets
These 
formlets are the main combinators for form input.
This 
formlet is rendered with 
render, which is passed
the input name, and results in the extracted 
binding.
This 
formlet is rendered with 
render, which is passed
the input name, and results in all the 
bindings that use the
name.
This 
formlet renders using an INPUT element with specified type
and arguments.
This 
formlet renders using an INPUT element with the TEXT type
and the attributes given in the arguments.
This 
formlet renders using an INPUT element with the PASSWORD
type and the attributes given in the arguments.
This 
formlet renders using an TEXTAREA element with attributes
given in the arguments.
This 
formlet renders using an INPUT element with the CHECKBOX
type and the attributes given in the arguments.
This 
formlet renders using an INPUT element with the RADIO type and the attributes given in the arguments.
This 
formlet renders using a sequence of INPUT elements of
RADIO type where each element gets its attributes from 
attrs
that share a single NAME. An element is checked if 
checked?
returns 
#t. Elements are followed by the results of
display. The result of processing this formlet is a single
element of the sequence.
This 
formlet renders using a sequence of INPUT elements of
CHECKBOX type where each element gets its attributes from
attrs that share a single NAME. An element is checked if
checked?  returns 
#t. Elements are followed by the
results of 
display. The result of processing this formlet is
a list of elements of the sequence.
This 
formlet renders using an INPUT element with the SUBMIT
type and the attributes given in the arguments.
This 
formlet renders using an INPUT element with the RESET type
and the attributes given in the arguments.
This 
formlet renders using an INPUT element with the FILE type
and the attributes given in the arguments.
This 
formlet renders using an INPUT element with HIDDEN type
and the attributes given in the arguments.
This 
formlet renders using an IMG element with the attributes
given in the arguments.
This 
formlet renders using a BUTTON element with the attributes
given in the arguments. 
button-text is the text that will
appear on the button when rendered.
This 
formlet renders using an SELECT element with the
attributes given with an OPTION for each element of the sequence. If
multiple? is 
#t, then multiple options may be
selected. An element is selected if 
selected? returns
#t. Elements are displayed with 
display.
This 
formlet renders using an SELECT element with the
attributes given with an OPTION for each element of the sequence. An
element is selected if 
selected? returns
#t. Elements are displayed with 
display.
Converts f’s output to a boolean, if it is equal to
#"on".
6.6 Utilities
A few utilities are provided for using 
formlets in Web applications.
Uses 
send/suspend and 
response/xexpr to send
f’s rendering (wrapped in a FORM tag with method
method whose action is the continuation URL (wrapped again
by 
wrapper)) to the client.  When the form is submitted,
the request is passed to the processing stage of 
f.