PDF hosted at the Radboud Repository of the Radboud University

PDF hosted at the Radboud Repository of the Radboud University
Nijmegen
The version of the following full text has not yet been defined or was untraceable and may
differ from the publisher's version.
For additional information about this publication click this link.
http://hdl.handle.net/2066/35194
Please be advised that this information was generated on 2017-06-17 and may be subject to
change.
T h e Im p lem en ta tio n o f iD a ta
A C ase S tu d y in G en eric P ro g ra m m in g
R inus Plasm eijer and P ete r A chten
Software Technology, Nijmegen Institute for Computing and Information Sciences,
Radboud University Nijmegen { rin u s, P.A chten}@ cs.ru.nl
A b s t r a c t . The iData Toolkit is a toolkit th at allows programmers to
create interactive, dynamic web applications with state on a high level of
abstraction. The key element of this toolkit is the iData element. An iData
element is a form th a t is generated automatically from a type definition
and th at can be plugged in in the web page of a web application. In
this paper we show how this automatic generation of forms has been
implemented. The technique relies essentially on generic program m ing.
It has resulted in a concise and flexible implementation. The iData Toolkit
is an excellent demonstration of the expressive power of modern generic
(poly-typical) programming techniques.
1
In tro d u ctio n
In th is p a p e r we p resent a novel approach to program m ing f o r m s in dynam ic
web applications. T he low level view, and sta n d a rd definition, of a form is th a t
of a collection of (prim itive) interactive elem ents, such as te x t in p u t fields, check
boxes, radio b u tto n s, pull down m enus, and so on, th a t provide th e application
user w ith a m eans to exchange stru c tu re d inform ation w ith th e web application.
Seen from th is p o in t of view, and if program m ed th a t way, creating forms results
in a lot of low level HTML coding. A high level view of forms is to th in k of th em
as being editors of stru c tu re d values of ap p ro p riate type. From th e type, the
low level realization can be derived autom atically. T his can be done once by the
too lk it developer. Seen from th a t p o in t of view, and if program m ed th a t way,
creating forms is all a b o u t creating d a ta types. T his results in a lot less code
plum bing an d no HTM L-coding a t all.
In th e iData Toolkit pro ject, we have ad o p ted th e high level view of forms
described above. We call these high level forms iData. An iData allows th e web
ap plication user to edit d a ta of some specified d a ta type. T he cu rren t value of
th a t d a ta ty p e is th e s ta te of th e iData. T he rendering of an iData is a form in the
low level view. R endering is determ ined com pletely by th e ty p e of th e sta te of
th e iData. H aving an explicit concept of sta te allows us to provide th e program ­
m er w ith fine grained control over its p e r s is te n c y . T he way a web application
works and looks is not exclusively determ ined by its iData. It also contains non­
in teractive web elem ents, such as te x t, headers, tables, and so on. In th e iData
Toolkit these are created by th e program m er by m eans of a set of d a ta types th a t
serve as a ty p ed HTML program m ing language. In sum m ary, th e iData Toolkit
has th e following m ain features:
— A n iData is a ty p e d in teractive u n it th a t can be plugged in a web page.
— A n iData has ty p ed sta te. T he program m er controls its persistence.
— W eb pages are p rogram m ed w ith d a ta types.
An approach as sketched above can be im plem ented in any program m ing lan­
guage w ith good su p p o rt for d a ta types and type-driven program m ing. M od­
ern functional program m ing languages such as Clean [21,3] and Haskell [20]
come w ith highly expressive ty p e system s. O ne exam ple of type-driven pro­
gram m ing is g en e ric p ro g ra m m in g [13,14,2], which has been b u ilt in in Clean
and GenericHVskell [17]. In th is p ap er we use Clean. We assum e th e reader is fa­
m iliar w ith functional an d generic program m ing. Clean specific language features
are explained in th e te x t.
Server side web applications are launched by th e web server as soon as a
request is received from a web browser. T he application produces th e requested
web page, an d th e n term in ates. Because of th is behavior, every web application
needs to create a solution to store, reload, and update its in te rm e d ia te state.
M any solutions to th is problem have been invented. Two of th em are server side
storage, an d enhancing th e web page w ith s ta te inform ation th a t is invisible to
th e application user. We ad o p t a com bination of these two solutions.
We show th a t generic program m ing provides us w ith concise and flexible
solutions for m ost of th e m ajo r aspects of web program m ing: serialization and
deserialization, storage an d retrieval of in term ed iate application states, p rinting
and parsin g of th e HTML d a ta ty p e language, tracking dow n and fixing edited
d a ta stru c tu re s of a rb itra ry type. In all, th e iData Toolkit pro ject is an excellent
case stu d y in generic program m ing.
T his p a p e r is stru c tu re d as follows. We first present th e HTML program m ing
language in Sect. 2. W ith th is language, th e application developer can create
a rb itra ry HTML pages. N ext, we show how th e iData Toolkit can au tom atically
generate form s o u t of iData elem ents in Sect. 3. T hese iData elem ents have a
sta te and a visualization th a t can be used by th e application developer in the
HTML pages. W hen a user m anipulates a page w ith iData, th e action of th e user
needs to be recovered, as well as th e state s of th e iData elem ents, and a new
collection of iData elem ents w ith possibly m odified sta te need to be created. We
show in Sect. 4 how th is can be done generically. T he last step is to o b tain a
good sep aratio n of th e iData logic and its visualization in Sect. 5. Sect. 6 gives
a sm all exam ple to give an im pression of th e expressiveness of th e iData Toolkit.
We discuss related work in Sect. 7 and conclude in Sect. 8.
2
P ro g ra m m in g S ta tic W eb P a g es
A server side web application is sta rte d by th e web server as soon as a request
is received from a client web browser. T he web application receives its in put
d a ta on std in an d sends its o u tp u t d a ta on std o u t . T he o u tp u t d a ta contains the
web page th a t is sent back by th e web server to th e client web browser. Hence,
th e purp o se of every web application is to produce a web page th a t reflects the
ap p licatio n ’s response to th e given in p u t. In addition, it has to retrieve sta te
inform ation th a t is eith er encoded in th e in p u t date, or has been stored on disk.
These sta n d a rd actions are perform ed by th e lib rary function
doHtml :: (*HSt ^ (Html,*HSt)) *World ^ *World
(In Clean, function argum ents are se p arate d by w hitespace in stead of ^ . T he
m ain function S ta r t of an interactive application has ty p e *World ^ *World. Clean
uses explicit m ultiple environm ent passing for handling pure effects. T he World
value represents th e ex ternal environm ent of an application. T he uniqueness
a ttrib u te * in front of th e ty p e c o n stru cto r guarantees single-threaded access to
values of th is ty p e [6, 7].)
T he application specific behavior is provided by th e program m er w ith the
function of ty p e
(*HSt ^ (Html,*HSt))
T he a b stra c t ty p e HSt collects all sta te s during th e co n struction of an HTML
page. We defer its discussion until Sect. 3.2. Here, we focus on th e Html type,
which is th e ro o t ty p e of a collection of algebraic d a ta types th a t ca p tu re HTML.
Html
Head
Rest
Frame
BodyTag
=
=
=
=
=
|
|
|
Html Head Rest
Head
[HeadAttr]
Body
[BodyAttr]
Frame
[FrameAttr]
A
[A_Attr]
STable
[T able_A ttr]
BodyTag [BodyTag]
EmptyBody
[HeadTag]
[BodyTag] | Frameset [Fram esetA ttr] [Frame]
[BodyTag]
| NoFrames [S td _ A ttr]
[BodyTag] | ... | Var [S td _ A ttr] S trin g
[[ BodyTag ]]
BodyTag contains th e fam iliar HTML tags, sta rtin g w ith a n ch o rs (a) and ending
w ith variables (Var) (in to ta l th ere are 76 HTML tags). T he la tte r th ree a lte r­
natives are for easy HTML generation: STable generates a 2-dim ensional table
of elem ents, BodyTag tu rn s lists of elem ents into a single elem ent, and EmptyBody
can be used as a zero elem ent. A ttrib u te s are encoded as FooAttr d a ta types.
T he lib ra ry function mkHtml :: S trin g [BodyTag] *HSt ^ (Html, *HSt) creates
a sim ple HTML page w ith given title and content.
mkHtml :: S trin g [BodyTag] *HSt ^ (Html,*HSt)
mkHtml t i t l e ta g s h s t
= (Html (Head [ ‘Hd_Std [S td _ T itle t i t l e ]] []) (Body [] ta g s ) , h st)
C onsider th e following exam ple of a tin y “Hello w orld” page.
S ta r t :: *World ^ *World
S ta r t world = doHtml (mkHtml "Hello World Example" [Txt "H ello W orld!"]) world
T he corresponding HTML code is
<head t i t l e = H ello World Example></head><body>Hello World!</body>
Basically, HTML can be encoded straightforw ardly into a set of algebraic d a ta
type. T here are some m inor com plications. In Clean, as well as in Haskell, all d a ta
co n stru cto rs have to be different. In HTML, th e sam e a ttrib u te nam es can appear
in different tags. F urtherm ore, certain a ttrib u te s, such as th e sta n d a rd attrib u te s,
can be used by m any tags. We do n o t w ant to re p ea t all these a ttrib u te s for
every tag, b u t group th em in a convenient way. To overcome these issues, we
use th e following nam ing conventions. (1 ) T he d a ta con stru cto r nam e represents
th e corresponding HTML language elem ent. (2 ) D a ta co n stru cto rs need to sta rt
w ith an uppercase ch aracter and m ay contain o th e r uppercase characters, b u t
th e corresponding HTML nam e is p rin ted in lower-case form at. (3 ) To ob tain
unique nam es, every d a ta co n stru cto r nam e is prefixed in a consistent way w ith
Foo_. W hen th e nam e is p rin ted we skip th is prefix. (4 ) A c o n stru cto r nam e is
prefixed w ith ‘ in case its nam e has to be com pletely ignored w hen p rinted. In
th is w ay any indirection to any collection of com m only used a ttrib u te s can be
m ade in th e d a ta ty p e w ith o u t causing any side effects w hen p rinted.
T his approach has th e following advantages. (1 ) O ne obtains a g ram m ar for
HTML which is convenient for th e program m er. (2 ) T he ty p e system elim inates
ty p e an d ty p in g errors th a t can occur w hen working in plain HTML. (3 ) We
can define a ty p e driven generic function for generating HTML code. (4 ) F u tu re
changes of HTML are likely to change th e algebraic d a ta types only.
T he generic p rin tin g ro utine gHpr im plem ents th e nam ing conventions dis­
cussed above, an d p rin ts th e correct HTML code.
g en eric gHpr a :: * F ile a ^ *F ile
( g e n e r ic g a :: T a declares a kind indexed fam ily of functions g th a t are over­
loaded in a w ith ty p e scheme T a. * F ile represents a file on disk th a t can be
u p d a te d in place, g u arded by th e uniqueness a ttrib u te .) Its definition is stra ig h t­
forw ard polytypical code; only th e CONS instance is special since it has to handle
th e conventions m entioned above. T his results in a universal HTML p rin ter in
less th a n 20 loc . For com pleteness we show its code.
gHpr{|String|}
file s
= file < < s
/ / Other basic type instances proceed analogously
gHpr{[]}
gx
file
gHpr{UnIT}
file
gHpr{pAlR}
ga gb f i l e
gHpr{EITHER} g l g r f i l e
gHpr{ElTHER} g l g r f i l e
gHpr{OBJECT} go
file
gHpr{CONS o f t} gc f i l e
| t.gcd_nam e.[0] ==
| t.g c d _ a r ity == 0
| t.g c d _ a r ity == 1
| otherw ise
where p r in t
xs
= f o ld l gx f i l e xs
_
= file
(PAIR a b) = gb (ga f i l e a) b
( lEFT
l) = g l f i l e l
(RIGHT r) = gr f i l e r
(OBJECT o) = go f i l e o
( cONS c)
= gc f i l e c
= f i l e <+ " " <+ p r in t t.gcd_name
= gc ( f i l e <+ " " <+ p r in t t.gcd_name <+ " = " ) c
= gc ( f i l e <+ " " <+ p r in t t.gcd_name
)c
= toLower o s tr ip p r e f ix
<<< is an overloaded o p erato r th a t w rites its second argum ent to th e first argu­
m ent of ty p e *F ile. o is function com position. <+ is a sh o rth an d for gHpr{*}.
g { k } selects th e overloaded function of kind
k of th e generic function fam ily g.)
D erived instances can be created for m ost of th e HTML types (73). T ypes such
as HeadTag an d BodyTag are n o t quite regular and require specialization (requiring
8 loc an d 90 loc respectively).
3
R en d erin g iData
In th e previous section we have shown how an iData Toolkit application developer
can pro g ram ‘raw ’ HTML code. T his HTML code m ay contain forms, b u t as we
have explained, we propose to create forms auto m atically from th e ty p e of the
d a ta th a t th e y are supposed to represent. In this section we show how to render
forms from th e sta te of iData. We first show how HTML rendering of iData is
tak en care of in Sect. 3.1, and th e n explain w h at sta te handling is required for
th is in Sect. 3.2.
3 .1
G e n e ra tin g F o rm s fro m T y p e s
Given a m odel value of ty p e m, th e n a form is generated by gForm:
g en eric gForm m : : Formld m *HSt ^ (Form m, *HSt)
T he form is rep resented by th e record ty p e (Form m). T he changed field of this
record holds if th e user has edited th e form. T he value field is its cu rrent value.
T he form field is th e actu al HTML rendering of th e form.
:: Form m = { changed::B ool, v a lu e::m , fo rm :: [ BodyTag] }
Because th e sta te of form s need to be stored (either in th e web page or on disk),
th e y have to be identified unam biguously. T his is w h at Formld values are for.
It is th e ta sk of th e application developer to use unam biguous nam es (S trings).
Formld values are created w ith one of th e functions {n, s, p}[d]FormId :: S t r i n g ^
Formld. In ad d itio n to th e nam e, th e program m er has control over th e life span
and edit m ode of th e iData elem ent.
:: Formld = { i d : : S t r i n g , life s p a n ::L ife s p a n , mode::Mode }
:: L ifespan = Page | Session | P e r s is te n t
:: Mode
= E d it | Display
T he life sp an of an iData elem ent is determ ined by {n, s, p}: its value is garbage
collected a u to m atically after each page creation (n), is stored p ersisten tly during
a session (s), or independent of sessions (p). B y default, values can be edited in
th e brow ser. If th e y should be displayed only, th e n one of th e {n, s, p}dFormId
functions can be used.
For basic types, gForm creates basic forms. We show th e code for integers, for
o th er basic ty p es th e code is analogous. (Value is used as a union ty p e for basic
types. UpdValue also includes selected con stru cto r nam es - last alternative.)
gForm {|lnt|} formid i hSt
$ (form ,hSt) = mklnput formid (IV i) (Updl i) hSt
= ({changed=False ,value=i ,forn=[form]} ,hSt)
: : UpdValue = Updl I n t | UpdR Real | UpdB Bool | UpdS S trin g | UpdC S trin g
: : Value
= IV
I n t | RV Real | BV Bool | SV S trin g | NQV S trin g
mklnput :: FormId Value UpdValue *HSt ^ (BodyTag, *HSt)
mklnput formid v a l updval hS t= :{cntr}
= ( Input [ Inp_Type Inp_Text, Inp_Value v a l , Inp_Size d e fsiz e
: case mode o f E dit
= [ Inp_Name
id e n tify
, ‘Inp_Std
[E ditB oxStyle]
, ‘Inp_Events [OnChange c a llC le a n ]]
Display = [ Inp_ReadOnly ReadOnly
, ‘Inp_Std
[DisplayBoxStyle] ]] ""
, {hSt & cn tr= cn tr+ l} )
where id e n tif y = encodeInfo (fo rm id .id , c n t r ,updval)
($ is a non recursive let definition which scope extends downwards, b u t n o t to its
right h a n d side. e= :p binds variable e to p a tte rn p; [e1: . . . , en :l] (w ith n > 0)
denotes a list th a t s ta rts w ith elem ents ei u p to en and th a t has a rem aining list
l; { r & f i = Vi} is a record equal to r, b u t w ith fields f having values v*; r . f
selects field f of record r.) Basic forms in D isplay m ode are read-only, and show
th is to th e user. Basic forms in E d it m ode need to ressurect th e web applica­
tio n on th e server side, an d provide it w ith th e pro p er inform ation. W henever
th e user edits th e value (OnChange), th e script callC lean =: " to c le a n (th is ) " is
called. T his scrip t sends th e sta te s of all forms and an id e n tific a tio n trip le t of
th e ed ited elem ent back to th e server, causing th e application to be sta rte d w ith
th e new d a ta . T he identification trip le t consists of th e unam biguous form iden­
tifier (fo rm id .id ), th e position of th e value in th e generic rep resen tatio n (cn tr),
and th e value th a t is ed ited (updval). T ogether w ith th e collection of all states,
th is is sufficient to recover th e old sta te and com pute th e n ex t sta te of th e web
ap plication (Sect. 4).
For th e generic co n stru cto rs (UNIT, PAIR, EITHER, FIELD, OBJECT, and CONS)
gForm proceeds polytypically. UNIT values are displayed as EmptyBody. (PAIR a b)
values are placed below each other. (EITHER a b) values proceed recursively and
display eith er th e ir left or right value. (OBJECT o) values proceed recursively. T he
form th a t corresponds w ith (CONS c) values requires m ore HTML program m ing.
gForm{CONS o f t}
$ (n c ,h s t)
= ( { changed
, value
, form
gc formid (CONS c) h st= :{ c n tr}
= gc form id c {hst & cntr= cntr+ l}
= n c . changed
= CONS n c . value
= [ STable [Tbl_CellPadding (P ix els 0)
,Tbl_CellSpacing (P ix els 0)]
[[s e l e c t o r ,BodyTag n c.fo rm ]]]
}, h s t )
where
allC onses= map (An ^ n.gcd_name) t.gcd_type_def.gtd_conses
consIndex= allConses??t.gcd_name
s e le c to r = S e le c t [Sel_Name "CS" : c s ty le ]
[Option
[ Opt_Value (encodelnfo (fo rm id .id , c n t r ,UpdC cons))
: if (j == conslndex) [O pt_Selected S e le c te d :o s ty le ] o s ty le ]
cons \ \ cons ^ allC onses & j ^ [0 .. ]]
( c s t y l e ,o sty le )
= case formid.mode of
E d it
^ ([ ‘Sel_Std [Std_Style w id th , EditB oxStyle]
, ‘Sel_Events [OnChange c a llC le a n ]] , [] )
Display ^ ([ ‘Sel_Std [Std_Style w id th , DisplayBoxStyle]
, Sel_D isabled D isabled] , [ ‘Opt_Std [D isplayBoxStyle]])
w idth
= "w idth:" +++ to S trin g d e fp ix e l +++ "px"
It generates a pull dow n m enu which entries correspond w ith all d a ta construc­
tors. In E d it m ode, th e user can select one of these d a ta constructors. Changes
are han d led in th e sam e way as w ith basic types, except th a t th e selected con­
stru c to r nam e is passed as argum ent. All in all, gForm’s im plem entation requires
140 h e.
Finally, gForm has been specialized for several sta n d a rd form elem ents. We
do not discuss th e ir im plem entation. It is basically in th e sam e style as th e In t
instance defined above.
3 .2
S to rin g F o rm S ta te s
In th e iData Toolkit, th e s ta te of a web application is th e set of th e sta te s of
all iData. W hile a page is generated, these sta te s are collected in th e ab stra ct
ty p e HSt. It extends th e Clean environm ent world :: World w ith a global counter
c n tr :: In p u tld to g enerate position values in th e generic rep resen tatio n of the
states, an d th e form s ta te s :: *FormStates th a t are con stru cted for a page.
:: *HSt
= { c n tr : : l n p u t l d , s ta te s ::* F o rm S ta te s , world::*W orld }
: : In p u tld :== In t
( : : T i t :== T ' i t declares th a t ty p e T i t is a synonym for ty p e T ' i t .)
FormStates stores th e serialized sta te s of forms to g eth er w ith th eir Formld value
and if th e y have been changed (either by th e user or by th e web application).
FormStates is basically an association list w ith a look up function fin d S ta te and
u p d a te function re p la c e S ta te . These require th e World environm ent in case of
P e r s is te n t forms. T he boolean result of fin d S ta te is tru e iff a previous sta te
was present. Finally, these functions are overloaded because of th eir use of the
generic serialization functions gParse and g P rin t.
fin d S ta te
:: Formld
*FormStates *World
(B ool, Maybe a , *FormStates , *World) | gParse{|*|} a
re p la c e S ta te :: Formld a *FormStates *World
^ (
*FormStates , *World) | gPrint{|*|} a
^
( | app en d s overloading class restrictions to a function type.)
In addition, FormStates stores th e edit op eratio n of th e user th a t caused the
ap plication to be launched. T he edit o p eratio n is determ ined by th e elem ent
th a t has been changed (the identification trip le t discussed in Sect. 3.1), and the
new value th a t has been entered by th e user. T his inform ation is retrieved from
FormStates by th e function
getU serE dit :: *FormStates ^
((Maybe a ,Maybe b ) , *FormStates)
| gParse{|*|} a & gParse{|*|} b
T his function is overloaded in its first result because th e d a ta is stored in seri­
alized form. For convenience, th e identification strin g of th e form th a t has been
edited by th e user is sto red separately. It is retrieved by
getU pdateld :: *FormStates ^ ( S tr in g ,*FormStates)
4
C rea tin g iData
In th e previous section we have shown th a t th e rendering of an iData is a form. If
th e application program m er plugs these forms in th e web page of th e application,
th e n th e y becom e available to th e application user, who can s ta rt m an ipulating
them . E very m an ip u latio n th a t changes th e cu rrent value of a form triggers the
execution of th e ap plication on th e server side. T he application has to figure out
why it has been launched. T here can be only th ree reasons:
1. N o fo r m w as edited, a n d there w as no p re vio u s sta te. Initialize all forms.
2. N o fo r m w as edited, a nd there are p re vio u s sta tes. Recover all previous states.
3. O ne fo r m w as edited, a n d i t had a p re vio u s sta te. C alculate th e new state,
given th e u p d a te inform ation and th e recovered previous state.
It is n o t th e ta sk of th e program m er to determ ine these actions. T his is delegated
to each ap plication of th e pivotal iData creation function, mkViewForm. T he pro­
gram m er uses th is function to create all of his iData. Because of th e com plexity of
mkViewForm, we first p resen t a slightly simplified version, viz. simplified_mkViewForm. T he full im plem entation of mkViewForm follows in Sect. 5.
In Sect. 4.1 we first show th e generic function gUpd th a t can u p d a te a selected
p a rt of any d a ta stru c tu re w ith a new value of th e correct type. T his essential
tool is used by simplified_mkViewForm in Sect. 4.2 to com pute a new sta te of a
form in case it has been ed ited by th e user.
4 .1
U p d a t i n g t h e S t a t e o f iData
T he function gUpd co n stru cts th e new m odel value of ty p e m of a form. It m ust be
a generic function because it needs to traverse th e generic d a ta rep resentation of
th e old m odel value in order to locate th e generic elem ent th a t has been changed.
T his location has been passed to th e application w ith th e identification trip let,
as explained in Sect. 3.1.
g e n e ric
gUpd m :: UpdMode m ^ (UpdMode, m)
:: UpdMode = UpdSearch UpdValue In p u tld | UpdCreate [ConsPos] | UpdDone
T he UpdMode ty p e represents th e two passes gUpd goes through: (UpdSearch newv
cnt) represents th e search for th e generic elem ent at location cnt w ith new value
newv, and (UpdCreate path) represents th e creation of new values for a selected
d a ta co n stru cto r th a t can be found at path (: : ConsPos = ConsLeft | ConsRight).
We illu stra te th e w orking of gUpd for basic types w ith th e case for integers
(the o th er cases for basic types are analogous). An existing value is replaced
w ith new som ew here in a generic value at position cnt if cnt = 0, otherw ise it is
not changed an d th e position is decreased (alternatives 1-2 of gUpd). T he default
value for new integers is 0 (alternative 3).
gUpd{|lnt}
gUpd{|lnt}
gUpd{|lnt}
gUpd{|lnt}
(UpdSearch (Updl new)0) _ = (UpdDone,new)
(UpdSearch v a l cnt) i = (UpdSearch v al (c n t-1 ) , i)
(UpdCreate l ) _ = (UpdCreate l ,0)
mode
i = (mode , i)
T he rem aining code of gUpd proceeds polytypically except for OBJECTs:
gUpd{OBJECT o f desc} gUpd_obj (UpdSearch (UpdC cname) 0) (OBJECT obj)
$ (mode,obj) = gUpd_obj (UpdCreate path) obj
= (UpdDone,OBJECT obj)
where p ath = getConsPath (hd [cons \ \ cons ^ desc.gtd_conses
| cons.gcd_name == cname ]
( [ f v \ \ v ^ l | p v ] is th e list co m p reh en sio n th a t creates a new list of values
f v w here each v comes from a list l provided th a t predicate p holds.) In this
case its new value is determ ined by th e nam e of th e selected d a ta co n structor
(cname). A t th a t point, gUpd sw itches from searching m ode into creation mode,
in order to create argum ents of th e d a ta constructor. T he function getConsPath
: : G enericConsD escriptor ^ [ConsPos] yields th e ro ute to th e desired d a ta con­
stru cto r.
4 .2
U p d a t i n g t h e iData
In th is section we define a sim plified version of th e mkViewForm function, viz.
simplified_mkViewForm. A t th e beginning of Sect. 4, we m entioned th e th ree sit­
u atio n s in which forms need to be u p d ated . T he function findFormlnfo perform s
th is case analysis. It m ust deserialize th e in p u t d a ta th a t has been passed to
th e web application an d look for th e form w ith th e given identification. For this
purpose it uses th e function decodelnput:
:: FormUpdate :== ( In p u tld ,UpdValue)
decodelnput :: Formld *FormStates *World
^ (Maybe FormUpdate ,( Bool,Maybe m,*FormStates ,*World)) | gParse{|*|} m
decodelnput form id f s world
$ (u p d a te id ,f s ) = getU pdateld fs
| u p d ateid == fo rm id .id
= case getU serE dit f s of
( ( Ju st ( s i d ,pos ,Updl i ) ,newi) ,fs ) / / case distinction on In t
$ p re v _ sta te = fin d S ta te {formid & id=sid} fs world
$ ni
= case newi o f (Ju st n i) ^ n i ; _ ^ i
= (Ju st (p o s,Updl n i ) ,p re v _ sta te )
( _ ,f s ) = . .. / / case distinction on other basic types
| otherw ise
= (N othing, fin d S ta te formid fs world)
T his function checks w hether th e iData elem ent th a t is identified by Formid has
been edited by th e user. If so, its exact location in th e generic rep resen tatio n is
re tu rn e d (of ty p e FormUpdate), as well as its cu rrent value (the result of using
fin d S ta te - see Sect. 3.2). For this reason, decodeinput requires th e FormStates
and World environm ents. It should be n o ted th a t fin d S ta te m ay fail to parse the
in p u t. T his m akes th e system type s a fe : if th e user has entered incorrect d a ta
(e.g. 42.0 in stead of 42 for an integer form ), th e n parsing fails, and th e previous
(correct) value is restored.
Given th e resu lt of decodeinput, findFormlnfo is able to determ ine th e reason
of executing th e applicatio n (the num bers to th e right coincide w ith th e cases in
th e beginning of th is section):
findForm lnfo :: Formid *FormStates *World ^ (B ool,Maybe m,*Form States,*World)
| gUpd{|*|} , gParse {|*|} m
findForm lnfo formid form States world
= case decodeinput formid form States world of
(Ju st ( c n t , newv) , ( changed, Ju st m, form States , w orld))
(3.)
$ m = if changed (snd (gUpd-jj*} (UpdSearch newv cnt) m)) m
= (T rue, Ju s t m, fo rm S tates,world)
(_ ,(_ , Ju st m,form States ,w orld))
(2.)
= (F a ls e , Ju s t m, fo rm S tates,world)
(_ ,(_ ,_ , form States ,w orld))
(1.)
= (F a ls e , N othing,fo rm S tates,world)
T he simplified_mkViewForm function brings everything together:
c la ss gHTML m | gForm, gUpd, g P r in t, gParse m
simplified_mkViewForm :: Formid m *HSt ^ (Form m, *HSt) | gHTML{|*|} m
simplified_mkViewForm formid init_m { s t a t e s ,world}
= calcnextView init_m (findForm lnfo formid s ta te s world)
where
calcnextView :: m (B ool,Maybe m,*Form States,*World) ^ (Form m,*HSt)
| gHTML{|*|} m
calcnextView init_m (isu p d a te d ,maybe_m,s t a t e s ,world)
$ m
= case maybe_m o f Nothing
= init_m
Ju st new_m = new_m
$ hSt
= { c n tr = 0 ,s ta te s = s ta te s ,world=world}
$ (m fo rm ,{states,world})
= gForm{|*|} formid m hSt
$ ( s t a t e s ,world) = re p la c e S ta te formid mform.value s ta te s world
$ mform
= {changed=isupdated,value=m ,form=mform.form}
$ hSt
= { c n tr = 0 ,s ta te s = s ta te s ,world=world}
= (mform,hSt)
simplified_mkViewForm first determ ines th e reason w hy th e web application was
s ta rte d using findFormlnfo. G iven th is inform ation, it can generate th e form for
th e correct value m, using gForm. Finally, th e new value of th e form is stored in
th e FormStates d a ta stru c tu re, and th e form and th e u p d a te d ad m in istratio n are
retu rn ed .
5
iData A b str a ctio n
In th e previous section we have shown how to co n stru ct web pages w ith iData
elem ents. W hen th e user m anipulates these iData elem ents, th e application re­
sponds w ith th e ap p ro p riate u p d a te action and generates a new page. T he iData
in a web page p resent a direct visualization of th e ir sta te values. Two final as­
pects are lacking:
1. A pplications usually im pose restrictions on edited values th a t go beyond the
expressiveness of th e ty p e system . For this reason th e y need to be able to
inspect edited values them selves, and perh ap s change th em into o ther values.
2. iData elem ents need to be able to present th eir values in any m anner th a t is
su itab le to th e application. In general this requires a different ty p e th a n th eir
s ta te type. T his im plies th a t presen tatio n concerns are n o t well sep arated
from logic concerns.
B ased on earlier work, we know th a t b o th aspects can be d ealt w ith by m eans of
a b stra ctio n [1]. We im prove upon th e m eth o d by providing a seam less integration
of ab stra c tio n w ith th e iData Toolkit. W ith abstractio n , th e application works
w ith iData th a t have sta te values of ty p e m, b u t th a t are visu a lized by m eans
of values of ty p e v. T his is a variant of th e well-known m odel(-controller)-view
p arad ig m [16]. W h a t is special ab o u t it in th is context, is th a t views are also
defined by m eans of a d a ta type, and hence can be handled generically in exactly
th e sam e way. T his is a powerful concept, and we have used it successfully in
th e past.
T he relatio n betw een a m odel m and its view v is given by th e following
collection of functions (iBimap m v):
: : IBimap m v = {
,
,
,
:: Changed
= {
,
toView
updView
fromView
resetV iew
isChanged
changedid
::
::
::
::
::
::
m ^ Maybe
Changed ^
Changed ^
Maybe (v ^
Bool
S trin g
v^
v^
v^
v)
v
v
m
}
}
M odel values are tran sfo rm ed to views w ith toView. It can use th e previous view
value if available. T he local behavior of an iData elem ent is given by updView.
Its first argum ent records if it has been changed (isChanged :: Bool), and the
unam biguous nam e of th e iData elem ent th a t has been changed (changedid ::
S trin g ). T his argum ent of ty p e Changed has th e sam e role in th e function fromView
which tran sfo rm s view values back to m odel values. Finally, resetView is an
o ptional sep arate norm alization a fte r th e local behavior function updView has
been applied.
A b stractio n is in co rp o rated in th e iData Toolkit by generalizing sim p lified _ mkViewForm in to th e following real lib rary function, mkViewForm. Its ty p e is:
mkViewForm :: FormId m (IBimap m v) »HSt ^ (Form m,»HSt) I gHTML{|*|} v
Its sig n atu re is alm ost identical to th a t of simplified_mkViewForm. It has an ad­
d itional argum ent of ty p e (IBimap m v), and it assum es th a t all th e generic m a­
chinery is available for th e view d a ta ty p e v in stead of m. Its im plem entation
has th e sam e stru c tu re as simplified_mkViewForm. T he function calcnextView is
m ore verbose because it needs to render th e view in stead of th e m odel value.
T his also explains why it is in general possible th a t th e creation of an iData ele­
m ent w ith m odel value m re tu rn s an iData elem ent w ith different o u tp u t value m‘.
T his is clearly illu stra te d by th e highlighted sections in th e a d a p ted definition
of calcnextView below.
mkViewForm : : FormId m (IB im ap m v) »HSt ^ (Form m, »HSt) I gHTML{|*|} v
mkViewForm form id init_m bm { s t a t e s ,world}
= calcnextView init_m bm (findFormInfo formid s ta te s world)
where
calcnextView :: m (IBim ap m v) (Bool, Maybe v ,»FormStates , »World)
^ (Form m, »HSt) I gHTML{l^} v
calcnextView init_m bm (isu p d a te d ,maybe_v,s t a t e s ,world)
J v
= bm .toView in it-m maybe jv
J v
= bm .updView isupdated v
J m
= bm .from V iew isupdated v
J v
= case bm .resetView of
N othing
= v
Just reset = reset v
J hSt
= { c n tr= G ,s ta te s = s ta te s ,world=world}
J (vform ,{ s ta te s ,world}) = gForm{|*|} formid v hSt
J ( s ta te s ,world)
= re p la c e S ta te formid vform .value s ta te s world
J mform
= {changed=isupdated, value=m , form = vform .form}
J hSt
= { c n tr= G ,s ta te s = s ta te s ,world=world}
= (mform,hSt)
T he function mkViewForm is a powerful tool to create form abstractio n s w ith.
F requently occurring p a tte rn s of this function have been ca p tu re d w ith w rapper
functions. C onsider mkEditForm below. It can be used as a ‘sto re ’ in D isplay mode,
or as a stra ig h t ed ito r in E d it mode.
mkEditForm :: FormId m »HSt ^ (Form m, »HSt) I gHtml{|*|} m
mkEditForm formid=: { mode} m h st
= mkViewForm form id m
{ toForm
= Anew old ^ case old o f (Ju st v) ^ v ; _ ^ new
, updForm = case mode o f E d it ^ A_ v ^ v ; D isplay ^ A_ _ ^ m
, fromForm = A_ v ^ v
, resetForm = Nothing } h st
6
E x a m p le
In order to get an im pression of th e expressiveness of th e iData Toolkit, we give
a sm all exam ple of a web application w ith which th e user can edit argum ents of
ty p e args th a t are applied to a given function of ty p e args ^ re s. T he application
displays th e resu lts of ty p e re s. T he function (apply name args f) generates the
page for function f w ith given name and initial argum ents args:
apply :: S trin g args (args ^ re s) *HSt ^ (Html, *HSt) | gHtml{|*|} args
& gHtml{|*|} re s
apply name args f hSt
$ (a rg sF ,hSt) = mkEditForm (nFormld "args") args hSt
$ (re s F , hSt) = mkEditForm (ndFormld "re s") (f argsF .value) hSt
= mkHtml "Function A pplication"
[ STable [] [[Txt nam e:argsF.form ], [Txt " = ":re sF .fo rm ]] ] hSt
Two iData are created. T he first is th e args form (argsF) for editing argum ents.
T he second is th e res form (resF) for displaying th e result, hence a d isplay Formid
is used. It uses th e value of th e argsF form to com pute th e p roper result. In the
page, th e form s are placed in tw o subsequent rows w ith an additional label.
In Fig. 1 tw o exam ples of th is application are shown. T he first exam ple tests
F ig . 1. (a )
Determine the prime index number. ( b ) Summing vector values.
th e function primeNr :: i n t ^ Maybe in t. If its argum ent is a prim e num ber, th en
it tells you which one it is (first, second, etc., w here 2 is th e first prim e num ber).
If it is n o t a prim e num ber, th e n Nothing is returned.
S ta r t world = doHtml (apply "primeNr" 1 primeNr) world
T he second exam ple illu strates th e fact th a t forms are generated from types. In
th is exam ple + is overloaded for a new ty p e for 2-dim ensional vectors, defined as
:: V = {vx: :R e a l, vy: :Real}. T he program is generated with:
S ta r t world = doHtml (apply "+" ( z ,z) (A (a,b) ^ a+b)) world
z = {vx=0. 0, vy=0. 0}
w h e re
7
R e la te d W ork
Lifting low-level W eb program m ing has triggered a lot of research. M any au th o rs
have worked on tu rn in g th e generation and m an ipulation of HTML (XML) pages
into a ty p ed discipline. E arly work is by W allace and R uncim an [25] on XML
transform ers in Haskell. T he Haskell CGI lib rary by M eijer [18] frees th e program ­
m er from dealing w ith CGI p rinting and parsing. H anus uses sim ilar types [12]
in Curry. T hiem an n co n stru cts ty p ed encodings of HTML in extended Haskell in
an increasing level of precision for va lid docum ents [23,24]. XML transform ing
program s w ith GenericHVskell has been investigated in UUXML [4]. E lsm an and
L arsen [10] have worked on ty p ed rep resentations of XML in ML [19]. O ur use of
A D Ts can be placed betw een th e single, generic ty p e used by M eijer and Hanus,
and th e collection of ty p es used by T hiem ann. It allows th e HTML definition to
be done com pletely w ith sep arate d a ta types for sep arate HTML elem ents.
iData com ponents are form ab stractions. A pioneer pro ject to experim ent
w ith form -based services is Mawl [5]. It has been im proved upon by m eans of
Powerforms [8], used in th e <bigw ig> pro ject [9]. These pro jects provide te m ­
p la tes which, roughly speaking, are HTML pages w ith holes in which scalar d a ta
as well as lists can be plugged in (Mawl), b u t also o th er te m p la tes (<bigw ig> ).
T h ey advocate com pile-tim e system s, because th is allows one to use ty p e sys­
tem s an d o th e r sta tic analysis. Powerforms reside on th e client-side of a web
application. T he ty p e system is used to filter out illegal user in p u t. T he use of
th e ty p e system is w hat th e y have in com m on w ith our approach. Because iData
are encoded by A D Ts, we get higher-order form s/pages for free.
W eb applications can be stru c tu re d w ith co n tin u a tio n s. T his has been done
by Hughes, w ith his arrow fram ew ork [15]. Q ueinnec sta te s th a t “A brow ser is
a device th a t can invoke co ntinuations m u ltip ly /sim u ltan eo u sly ” [22]. G raunke
et al [11] have explored co ntinuations as (one of three) functional com pilation
technique(s) to tran sfo rm sequential interactive program s to CGI program s. O ur
approach is sim pler because for every page we have a com plete (set of) m odel
value(s) th a t can be sto red and retrieved generically in a page. A n application
is resu rrected sim ply by recovering its previous state.
8
C o n clu sion s
T here are m any tools an d script languages for developing web pages. For in te r­
active web services m an y pages have to be produced in sequence th a t in teract
w ith th e user in a consistent and reliable way. Defining such behavior is difficult.
W ith th e iData Toolkit interactive web applications can be specified on a high
level of ab stractio n . W eb applications consist of sta tic HTML p a rts, usually for
p resen tatio n purposes, an d interactive forms, for user interaction. T his distinc­
tio n is explicit in th e toolkit. We provide an a b stra c t version of forms, iData.
Form s are g en erated from iData, and can be plugged in in a rb itra ry HTML pages.
T he HTML pages are co n stru cted using a lib ra ry of algebraic d a ta types. This
elim inates m any ty p e errors, and provides good docu m en tatio n for p rogram ­
m ers. T he program m er can create in trica te relationships betw een iData, using
sta n d a rd functional program m ing techniques. A lthough th e im plem entation of
th e to o lk it using advanced program m ing techniques, we have kept th e API of
th e to o lk it as sim ple as possible. Basic knowledge of functional program m ing is
sufficient to get sta rte d .
A high level of ab stra c tio n has to be realized using th e very low level web
technology. Yet th e im plem entation of th e iData Toolkit is concise, elegant, and
efficient. T his is m ainly due to th e su p p o rt for generic program m ing in Clean.
Generic functions are used for generating HTML code, for serialization and de­
serialization of values of any Clean type, for th e conversion of Clean d a ta into
in teractive HTML forms, an d th e au to m atic u p d a te of values of any ty p e w hen a
form is changed. T his m akes th e iData Toolkit an excellent case stu d y in generic
program m ing for th e real world.
A ck n o w led g em en ts
Ja n K u p er coined th e nam e iData for our editor com ponents. P ieter K oopm an
provided in p u t for th e gUpd function. P aul de M ast kindly provided us w ith a
web server ap plication w ritte n in Clean which has allowed us to readily te st the
iData Toolkit. Javier P om er Tendillo, as an E rasm us guest, has been very helpful
in settin g u p th e iData Toolkit, and find o u t th e n itty -g ritty details of HTML
program m ing.
R eferen ces
1. P. Achten, M. van Eekelen, and R. Plasmeijer. Compositional Model-Views with
Generic Graphical User Interfaces. In Practical Aspects o f Declarative Program­
ming, PADL04, volume 3057 of LN C S, pages 39-55. Springer, 2004.
2. A. Alimarine. Generic Functional Programming - Conceptual Design, Im plem en­
tation and Applications. PhD thesis, University of Nijmegen, The Netherlands,
2005. ISBN 3-540-67658-9.
3. A. Alimarine and R. Plasmeijer. A Generic Programming Extension for Clean.
In T. Arts and M. Mohnen, editors, The 13th International workshop on the Im ­
plem entation o f Functional Languages, I F L ’01, Selected Papers, volume 2312 of
LN C S, pages 168-186. Alvsjo, Sweden, Springer, Sept. 2002.
4. F. Atanassow, D. Clarke, and J. Jeuring. UUXML: A Type-Preserving XML
Schema-Haskell D ata Binding. In International Sym posium on Practical Aspects of
Declarative Languages (P A D L ’04), volume 3057 of LN C S, pages 71-85. Springer­
Verlag, June 2004.
5. D. Atkins, T. Ball, M. Benedikt, G. Bruns, K. Cox, P. Mataga, and K. Rehor.
Experience with a Domain Specific Language for Form-based Services. In Usenix
Conference on D om ain Specific Languages, Oct. 1997.
6. E. Barendsen and S. Smetsers. Uniqueness typing for functional languages with
graph rewriting semantics. In M athem atical Structures in Com puter Science, vol­
ume 6, pages 579-612, 1996.
7. E. Barendsen and S. Smetsers. Graph Rewriting Aspects o f Functional Program­
ming, chapter 2, pages 63-102. World scientific, 1999.
8. C. Brabrand, A. M0ller, M. Ricky, and M. Schwartzbach. Powerforms: Declarative
client-side form field validation. World Wide Web Journal, 3(4):205-314, 2000.
9. C. Brabrand, A. M0ller, and M. Schwartzbach. The <bigwig> Project. In A C M
Transactions on Internet Technology (T O IT ), 2002.
10. M. Elsman and K. F. Larsen. Typing XHTML Web applications in ML. In In ­
ternational Sym posium on Practical Aspects o f Declarative Languages (PAD L ’04),
volume 3057 of L N C S , pages 224-238. Springer-Verlag, June 2004.
11. P. Graunke, S. Krishnamurthi, R. Bruce Findler, and M. Felleisen. Automatically
Restructuring Programs for the Web. In M. Feather and M. Goedicke, editors, Pro­
ceedings 16th IE E E International Conference on A utom ated Software Engineering
( A S E ’01). IEEE CS Press, Sept. 2001.
12. M. Hanus. High-Level Server Side Web Scripting in Curry. In Proc. o f the Third In ­
ternational Sym posium on Practical Aspects o f Declarative Languages (PAD L ’01),
pages 76-92. Springer LNCS 1990, 2001.
13. R. Hinze. A new approach to generic functional programming. In The 27th A nnual
A C M S IG P L A N -S IG A C T Sym posium on Principles o f Programming Languages,
pages 119-132. Boston, Massachusetts, January 2000.
14. R. Hinze and S. Peyton Jones. Derivable Type Classes. In G. Hutton, editor, 2000
A C M S IG P L A N Haskell Workshop, volume 41(1) of E N T C S. Montreal, Canada,
Elsevier Science, 2001.
15. J. Hughes. Generalising Monads to Arrows. Science o f Com puter Programming ,
37:67-111, May 2000.
16. G. Krasner and S. Pope. A cookbook for using the Model-View-Controller user
interface paradigm in Smalltalk-80. Journal o f Object-Oriented Programming,
1(3):26-49, August 1988.
17. A. Loh, D. Clarke, and J. Jeuring. Dependency-style Generic Haskell. In Pro­
18.
19.
20.
21.
ceedings of the eighth A C M S IG P L A N International Conference on Functional
Programming (IC F P ’03), pages 141-152. ACM Press, 2003.
E. Meijer. Server Side Web Scripting in Haskell. Journal o f Functional Program­
m ing , 10(1):1-18, 2000.
R. Milner, M. Tofte, R. Harper, and D. MacQueen. The D efinition o f Standard
M L (Revised ). MIT Press, 1997.
S. Peyton Jones and Hughes J. et al. Report on the programming language Haskell
98. University of Yale, 1999. http://w w w .haskell.org/definition/.
R. Plasmeijer and M. van Eekelen. Concurrent C L E A N Language Report (version
2.0), December 2001. h ttp://w w w .cs.ru.nl/~ clean/.
22. C. Queinnec. The influence of browsers on evaluators or, continuations to pro­
gram web servers. In Proceedings F ifth International Conference on Functional
Programming (IC F P ’00), Sept. 2000.
23. P. Thiemann. WASH/CGI: Server-side Web Scripting with Sessions and Typed,
Compositional Forms. In S. Krishnamurthi and C. Ramakrishnan, editors, Prac­
tical Aspects o f Declarative Languages: 4th International Sym posium , PAD L 2002,
volume 2257 of L N C S , pages 192-208, Portland, OR, USA, January 19-20 2002.
Springer-Verlag.
24. P. Thiemann. A Typed Representation for HTML and XML Documents in Haskell.
Journal o f Functional Programming , 2005. Under consideration for publication.
25. M. Wallace and C. Runciman. Haskell and XML: Generic combinators or typebased translation? In Proc. o f the Fourth A C M S IG P L A N Intnl. Conference
on Functional Programming (IC F P ‘99), volume 34-9, pages 148-159, N.Y., 1999.
ACM.