Generating Multi-User Workflow Systems for the WWWeb



With Clean’s new i-Tasks library you can generate a multi-user workflow system for the web.

It makes use of the i-Data library with which web forms can be generated and handled automatically given a static type of a data structure.

These Clean libraries use generic programming techniques which enables a very compact and concise notation.






If you want to use i-Tasks you



More information:


Have a look at the DEMO’s and the corresponding CLEAN CODE:





Below we give a short idea about what  i-Tasks are. More examples are given in the DEMO page.


i-Tasks: generating an editor for any (first order) type


Here follows the code of a complete i-Tasks application written in Clean:


module example


import StdEnv, StdHtml


Start world = doHtmlServer (singleUserTask 0 True simple) world


simple :: (Task Int)
simple = editTask "Done" createDefault


The first two lines are standard, the third lines is the main function. It automatically links in an http server (doHtmlServer ) for easy testing of a user defined web application defined by the function simple.  This function uses the basic i-Tasks editor editTask. It can generate an html form editor for any type. The editor does need an initial value of this type. But in this case a default value (0) is generated by createDefault.  The function createDefault can create a default value for any first order type. With the button "Done" the user can indicate that the i-Task editor is finished. This example generates the following web page in which repeatedly an Integer value can be typed in until the "Done" button is pressed.



Only Integer values will be accepted by the application, because the type of simple is (Task Int). By only changing the type of the function simple a different form is generated, e.g. if the type is changed into (Task (Int, Real)) one obtains a box for typing in an Integer and a Real value:



simple :: (Task (Int, Real))
simple = editTask "Done" createDefault



This works for any first order type one can define in Clean (algebraic data types such as lists, trees, for types like arrays and records), hence for user defined types as well. For instance for record types:


:: Person =        { name             :: String

                         , street            :: String

                         , number          :: Int

                         , zipCode         :: String

                         , town             :: String

                         , born              :: HtmlDate



simple :: (Task Person)

simple = editTask "Done" createDefault


derive gForm Person; derive gUpd   Person; derive gParse Person; derive gPrint  Person; derive gerda  Person;



For a user defined type one has to ask the compiler to derive instances for the generic functions that are being used to generate, store and handle web forms:


i-Tasks: combining tasks


Monads are used (yes, we have them in Clean, and they are type safe thanks to Clean’s uniqueness typing) for sequencing i-Tasks. For instance if one want to type in two Integers in a sequence and add up their values, one defines:


simple :: (Task Int)


=                                  editTask "Done" createDefault

            =>> \v1 ->          editTask "Done" createDefault

            =>> \v2 ->          [Txt "+", Hr [] ]

                                   !>> return_D (v1 + v2)




First an integer value is asked from the user returning the value v1, then another one is asked returning the value v2, then some html code is printed [Txt "+", Hr [] ] and the sum of these two values is returned and printed  return_D (v1 + v2). Notice that the code of an i-Tasks application is very easy to read, certainly for functional programmers. The reason is the following. Although the application is started from scratch every time a new event is received from the client, it remembers its state and finds its way back to the point where it was handling tasks the previous time. So the programmer can read the code “line by line” although it is not executed in this way at all. The application remembers which tasks are finished and which tasks still have to be done. Another reason for the simplicity of the code is that almost all information is saved and retrieved automatically. Information can be stored in html pages, in files or in a relational database just by changing an option.


The library offers many combinators for handling tasks, such as:


In fact, all workflow patterns as they are commonly can be found in commercial workflow systems are supported.

But there are many advantages over many commercial systems.


To see more complicated examples: goto the demo page.


i-Tasks: multi-user tasks


Tasks can be assigned to different users. Each user has a unique id. This id can be assigned (@::) to any task or any combination of tasks. For instance in our simple example we can specify that the first number has to be given by user 1, the second by user 2, the result is shown to the default user (which is user 0).



simple :: (Task Int)


=                                  1  @:: editTask "Done" createDefault

            =>> \v1 ->          2  @:: editTask "Done" createDefault

            =>> \v2 ->          [Txt "+", Hr [] ]

                                   !>> return_D (v1 + v2)


So, all participants in an i-Task workflow application work with one and the same application. This makes it relatively easy to reason about the system. The system can deal with multiple users and will show to each user only the part of the information which is intended for him or her. Login scenario’s can be programmed as an i-Task as well.


To see more complicated examples: goto the demo page.