i-Tasks - interactive workflow tasks for the WEB

Download Report

Transcript i-Tasks - interactive workflow tasks for the WEB

i-Tasks
interactive workflow Tasks
for the WWWEB
___________
Rinus Plasmeijer
University of Nijmegen
www.cs.ru.nl/~clean
Clean

Introduction

Defining Interactive Multi-user Workflow Systems for the web





Implementation




Defining a simple task: an editor for a web form
Combinators for constructing tasks
Assigning tasks to users
Logging in to a Multi-user Workflow System
Basic idea of generic programming
Generic functions for handling web forms: i-Data
Implementation of i-Tasks
Conclusion & Future Research
2
Clean

Introduction

Defining Interactive Multi-user Workflow Systems for the web





Implementation




Defining a simple task: an editor for a web form
Combinators for constructing tasks
Assigning tasks to users
Logging in to a Multi-user Workflow System
Basic idea of generic programming
Generic functions for handling web forms: i-Data
Implementation of i-Tasks
Conclusion & Future Research
3
Clean

State-Of-The-Art Pure Functional Programming Language

Lazy, pure, higher order functions and types, lots of features


Clean is an extended subset of Haskell
Haskell is an extended subset of Clean
– de-facto standard (GHC)

Extra facilities in Clean:
 I/O: Uniqueness Typing <-> Monads
 Re-usage: Generic programming included <-> Generic Haskell preprocessor
 Hybrid typing: Static as well as Dynamic typing <-> poor man's Dynamics
 Type safe plug-inns: run-time storing and loading of functions
 Sparkle: Cleans dedicated theorem prover
 Gast: Cleans test system

Clean Compiler is fast (4th place language shootout, after 3 C compilers !)
 2 third party Haskell -> Clean compilers
 Haskell / Clean code can be combined in next Clean release
4
Why workflows?

Dutch STW grant “Demand Driven Workflows”
New approach on specifying workflows making use of "lazy evaluation"

University:
TU Eindhoven (Van der Aalst)
RadBoud University Nijmegen (Plasmeijer)
Industry:
Palas Athena (Eindhoven): producer of commercial workflow system
ABZ (Utrecht): uses workflow system for developing applications
AIA (Nijmegen): produces content management systems
i -Tasks
First, "simple" approach to make a quick start
 Already offers more functionality than found in commercial systems
 “i –Tasks: Executable Specifications of Interactive Workflow Systems for the Web”,
R.Plasmeijer, P.Achten, P.Koopman, ICFP 2007.
 see: http://www.cs.ru.nl/~rinus/iTaskIntro.html
5
i -Tasks Approach I

Study “Workflow Patterns” (Van der Aalst, ter Hofstede, Kiepuszewski, Barros)
 > 30 products: Staffware, Cosa, InConcert, Eastman Software, FLOWer,
Domino Workflow, Meteor, Mobile, MQSeries, Forte Conductor,
Verve, Visual WorkFlo, Changengine, I-Flow, SAP R/3 Workflow
 patterns: sequence, recursion, exclusive choice, multiple choice,
split/merge (parallel or, parallel and, discriminator), ...

All Workflow Patterns can "straightforwardly" be implemented in Clean
 Using i-Data: Clean library for handling interactive web forms
 Using generic functions: highly reusable functions, given a type they
 generate an html form
 deal with any change made by a user in a form
 enable separation between model (value returned) and view (the looks)
 automatically store and retrieve info in a file or database
6
i -TasksApproach II
Disadvantages i –Tasks over Commercial Systems
 No nice graphical interface for defining workflows: just Clean code
 A first prototype, limited interfaces to real world, lots of additional wishes
Advantages i –Tasks over Commercial Systems
Declarative, executable specification
Workflows are statically typed, input type checked as well
Highly reusable code: polymorphic, overloaded, generic
Workflows are dynamically constructed
 Flow can depend on the actual contents
 Fully compositional
 Higher order tasks: shift work flows to someone else
 It generates a multi-user web enabled (!) workflow system




 < 1000 lines of code based on Clean’s i-Data library for the web
7
i -Tasks Approach III
 Web applications are not easy to write


Interactive applications for the Web are hard to programme
»
No direct connection between User on Client <--> Application on Server
»
Web has no notion of state: application has to store information
Multi-user applications even harder
Offer a layer which hides as many annoying details as possible.
i –Tasks - Embedded Domain Specific Language:
Workflow Specification Language which generates a multi-user system for the web.
i –Tasks – Workflow Combinator Library for Clean
8
Clean

Introduction

Defining Interactive Multi-user Workflow Systems for the web





Implementation




Defining a simple task: an editor for a web form
Combinators for constructing tasks
Assigning tasks to users
Logging in to a Multi-user Workflow System
Basic idea of generic programming
Generic functions for handling web forms: i-Data
Implementation of i-Tasks
Conclusion & Future Research
9
A very small *complete* example I
module example
import StdEnv, StdHtml
Start world = doHtmlServer (singleUserTask 0 True simple) world
simple :: (Task Int)
simple = editTask "Done" createDefault
10
Testing an i –Tasks application
Browser
Changes in Forms
Htmlcode
Http 1.0 Web Server
Clean Application
i –Tasks Application
11
Final setting of an i –Tasks application
Browser
Htmlcode
Changes in Forms
Http 1.1 Web Server
i –Tasks Application 1
i –Tasks Application 2
i –Tasks Application n
12
A very small *complete* example II
module example
import StdEnv, StdHtml
Start world = doHtmlServer (singleUserTask 0 True simple) world
simple :: (Task (Int, Real))
simple = editTask "Done" createDefault
13
A very small *complete* example III
simple :: (Task [Int])
simple = editTask "Done" createDefault
14
A very small *complete* example IV
:: Person = { name
, street
, number
, zipCode
, town
, born
}
:: String
:: String
:: Int
:: String
:: String
:: HtmlDate
simple :: (Task Person)
simple = editTask "Done" createDefault
derive
derive
derive
derive
derive
gForm Person
gUpd Person
gParse Person
gPrint Person
gerda Person
15
editTask
editTask :: String a  (Task a)
:: Task a
| iData a
// an editor for values of type "a"
// an interactive task
A task consist of an amount of work to be performed by the user involving ≥ 0 interactions
It is either not active, active, or finished.
16
editTask uses generic functions
class
class
class
class
class
class
iData a
iCreateAndPrint a
iCreate a
iPrint a
iParse a
iSpecialStore a
|
|
|
|
|
|
gForm {|*|} , iCreateAndPrint, iParse, iSpecialStore a
iCreate, iPrint a
gUpd {|*|} a
gPrint {|*|} a
gParse {|*|} a
gerda {|*|}, TC a
It requires the instantiation of several generic functions for type "a" e.g.
gForm
html form creation,
gUpd
form handling,
gParse
parsing,
gPrint
printing,
gerda
data storage I a relational database,
TC
Conversion to and from Dynamics, option used to store functions
which can all, on request, automatically be derived by the compiler !
17
Options
A task or combination of tasks, can have several options:
class (<<@) infixl 3 b :: (Task a) b  Task a
instance <<@
,
,
,
:: Lifespan
:: StorageFormat
:: Mode
:: GarbageCollect
Lifespan
StorageFormat
Mode
GarbageCollect
//
//
//
//
default:
default:
default:
deafult:
Session
PlainString
Edit
Collect
= Database | TxtFile | Session | Page | Temp
= StaticDynamic | PlainString
= Edit | Submit | Display | NoForm
= Collect | NoCollect
18
A very small *complete* example IV
simple :: (Task Person)
simple = editTask "Done" createDefault
19
A very small *complete* example IV Submit
simple :: (Task Person)
simple = editTask "Done" createDefault <<@ Submit
20
A very small *complete* example IV, Submit, Database
simple :: (Task Person)
simple = editTask "Done" createDefault <<@ Submit <<@ Database
21
A very small *complete* example IV, Submit, TxtFile
simple :: (Task Person)
simple = editTask "Done" createDefault <<@ Submit <<@ TxtFile
22
Clean

Introduction

Defining Interactive Multi-user Workflow Systems for the web





Implementation




Defining a simple task: an editor for a web form
Combinators for constructing tasks
Assigning tasks to users
Logging in to a Multi-user Workflow System
Basic idea of generic programming
Generic functions for handling web forms: i-Data
Implementation of i-Tasks
Conclusion & Future Research
23
Sequencing of tasks
Sequencing / composition of tasks (monadic style):
(=>>) infix 1
(#>>) infixl 1
:: (Task a) (a  Task b)
:: (Task a) (Task b)
 Task b
 Task b
Returning plain values as a Task value
return_V
:: a
 Task a
| iData a
24
Prompting
Returning plain values as a Task value (showing the returned value):
return_D
:: a
 Task a
| iData a
Prompting as long as / as soon as a task is activated:
(?>>) infix 5
(!>>) infix 5
:: [BodyTag] (Task a)
:: [BodyTag] (Task a)
 Task a
 Task a
| iData a
| iData a
25
Html code
A Clean Algebraic Data Type (ADT) is defined isomorphic with Html Code

Provides a grammar only allowing syntactic "correct" html code

Type error otherwise

A generic function is used to generate Html code out of it
:: BodyTag
=A
| Abbr
| Acronym
| Address
| Applet
| Area
|B
…
| Txt
|U
| Ul
| Var
[A_Attr] [BodyTag]
[Std_Attr] String
[Std_Attr] String
[Std_Attr] String
[Applet_Attr] String
[Area_Attr]
[Std_Attr] String
//
//
//
//
//
//
//
link ancor <a></a>
abbreviation <abbr></abbr>
acronym <acronym></acronym>
address <address></address>
applet <applet></applet>
link area in an image <area>
bold <b></b>
String
[Std_Attr] String
[Ul_Attr] [BodyTag]
[Std_Attr] String
//
//
//
//
plain text
underlined text <u></u>
unordered list <ul></ul>
variable text <var></var>
26
Sequence of iTasks
sumInt :: (Task Int)
sumInt
=
editTask "Done" createDefault
=>> \v1 
editTask "Done" createDefault
=>> \v2 
[Txt "+", Hr [] ]
!>> return_D (v1 + v2)
27
Simple Coffeemachine (1/3)
28
Simple Coffeemachine (2/3)
simpleCoffee = foreverTask SimlpeCoffeeMachine
SimlpeCoffeeMachine :: (Task String)
SimlpeCoffeeMachine
=
[Txt "Choose product:",Br,Br]
?>> chooseTask
[ ("Coffee", return_V ("Coffee"))
, ("Tea",
return_V ("Tea"))
]
=>> \product 
[Txt ("Enjoy your " <+++ product)]
?>> chooseTask
[ "OK“, return_V product]
29
Simple Coffeemachine (3/3)
simpleCoffee = foreverTask SimlpeCoffeeMachine
SimlpeCoffeeMachine :: (Task String)
SimlpeCoffeeMachine
=
[Txt "Choose product:",Br,Br]
?>> chooseTask
[ ("Coffee", return_V ("Coffee"))
, ("Tea",
return_V ("Tea"))
]
=>> \product 
[Txt ("Enjoy your " <+++ product)]
?>> buttonTask "OK" (return_V product)
30
All kinds of task combinators
Loop:
foreverTask
:: (Task a)
 (Task a)
| iData a
Choose 1 out of n:
chooseTask
:: [(String,Task a)]
 (Task a)
| iData a
Choose m out of n:
mchoiceTasks
:: [(String,Task a)]
 (Task [a])
| iData a
Or task, do all in any order, finish as soon as one completes
(-||-) infixr 3
:: (Task a) (Task a)
 (Task a)
orTasks
:: [(String,Task a)]
 (Task a)
| iData a
| iData a
And task, do all in any order, and finish when all completed
(-&&-) infixr 4
:: (Task a) (Task b)
 (Task (a,b))
andTasks
:: [(String,Task a)]
 (Task [a])
| iData a & iData b
| iData a
Treat user defined function as a new task: enables recursion
newTask
:: String (Task a)
 (Task a)
| iData a
31
Coffeemachine (1/3)
32
Coffeemachine (2/3)
infCoffee = foreverTask CoffeeMachine
CoffeeMachine :: Task (String, Int)
CoffeeMachine
=
[Txt "Choose product:", Br, Br]
?>> chooseTask
[ ("Coffee: 100", return_V (100,"Coffee"))
, ("Cappucino: 150", return_V (150,"Cappucino"))
, ("Tee: 50",
return_V (50, "Tee"))
, ("Choclate: 100", return_V (100,"Choclate"))
]
=>> \(toPay, product) [Txt ("Chosen product: " <+++ product), Br, Br]
?>> getCoins (toPay, 0)
=>> \(cancel, returnMoney)
 let nproduct = if cancel "Cancelled" product in
[Txt ("product = " <+++ nproduct <+++ ",
returned money = " <+++ returnMoney), Br, Br]
?>> buttonTask "Thanks" (return_V (nproduct, returnMoney))
33
Coffeemachine (3/3)
getCoins :: (Int, Int) -> Task (Bool, Int)
getCoins (toPay, paid) = newTask "getCoins" getCoins`
where
getCoins`
=
[Txt ("To pay: " <+++ toPay), Br, Br]
?>> chooseTask [ (c +++> " cts", return_V (False, c)) \\ c  coins ]
-||buttonTask "Cancel" (return_V (True, 0))
=>> handleMoney
handleMoney (cancel, coin)
| cancel
= return_V (True, paid)
| toPay - coin > 0
= getCoins (toPay - coin, paid + coin)
| otherwise
= return_V (False, coin - toPay)
coins = [ 5, 10, 20, 50, 100, 200 ]
34
Clean

Introduction

Defining Interactive Multi-user Workflow Systems for the web





Implementation




Defining a simple task: an editor for a web form
Combinators for constructing tasks
Assigning tasks to users
Logging in to a Multi-user Workflow System
Basic idea of generic programming
Generic functions for handling web forms: i-Data
Implementation of i-Tasks
Conclusion & Future Research
35
Multi-user combinators
Multi-user :
(@:) infix 3
(@::) infix 3
:: (String, Int) (Task a)
:: Int (Task a)
 (Task a)
 (Task a)
| iData a
| iData a
36
Multi-User example: Review Task
37
Multi-User example: Review Task
38
Review Task (1/3)
:: Review = Approved | Cancelled | NeedsRework TextArea | Draft
reviewTask :: a  (Task Review)
| iData a
reviewTask v
= [toHtml v, Br, Br]
?>> chooseTask
[ ("Rework", editTask "Done" (NeedsRework createDefault) <<@ Submit)
, ("Approved", return_V Approved)
, ("Reject",
return_V Rejected)
]
39
Review Task (2/3)
taskToReview :: Int (a, a  Task a)  Task (a, Review) | iData a
taskToReview reviewer (val, task)
= newTask "taskToReview" taskToReview`
where
taskToReview`
=
task val
=>> \newval 
reviewer @:: reviewTask newval
=>> \review 
[Txt ("Reviewer " <+++ reviewer <+++ " says ") , toHtml review, Br]
?>> editTask "OK" Void
#>>
case review of
(NeedsRework _)  taskToReview reviewer (newval, task)
else
 return_V (newval, review)
40
Review Task (3/3)
:: QForm =
{ toComp
, startDate
, endDate
, estimatedHours
, description
, price
}
:: String
:: HtmlDate
:: HtmlDate
:: Int
:: TextArea
:: Real
startTask :: Task (QForm, Review)
startTask = taskToReview 1 (createDefault, mytask)
mytask :: a  (Task a) | iData a
mytask v = [Txt "Fill in Form:", Br, Br]
?>> editTask "TaskDone" v <<@ Submit
41
Higher-Order Tasks
Tasks not only deliver values, they may deliver a task under development !
:: TClosure a
:: Maybe a
= TClosure (Task a)
= Just a | Nothing
orTask variant: a task is either finished, or interrupted if the stop task is finished sooner
(-!>) infix 4 :: (Task stop) (Task a)  (Task (Maybe stop, TClosure a)) | iData stop & iData a
42
Multi-User example: delegate a task
43
Delegate a Task
delegateToSomeone :: Int (Task a) [Int]  (Task a) | iData a
delegateToSomeone me task set = newTask "delegateToSomeone" doDelegate
where
doDelegate
=
orTasks [ ("Waiting for " <+++ who
, who @:: chooseTask [("I Will Do It“, return_V who)]
) \\ who  set
]
=>> \volunteer  volunteer @:: stopIt -!> task
=>> \(stopped, TClosure task) 
if (isJust stopped) (delegateToSomeone me task set) task
stopIt
= stop -||- (me @:: stop)
stop
= chooseTask [("Stop“, return_V True)]
44
Clean

Introduction

Defining Interactive Multi-user Workflow Systems for the web





Implementation




Defining a simple task: an editor for a web form
Combinators for constructing tasks
Assigning tasks to users
Logging in to a Multi-user Workflow System
Basic idea of generic programming
Generic functions for handling web forms: i-Data
Implementation of i-Tasks
Conclusion & Future Research
45
Login handling types and functions …
:: Accounts s
:: Account s =
:: Maybe a
:== [Account s]
{ login
, uniqueId
, state
}
{ loginName
, password
}
= Just a | Nothing
addAccount
removeAccount
changeAccount
:: (Account s) (Accounts s)  (Accounts s)
:: (Account s) (Accounts s)  (Accounts s)
:: (Account s) (Accounts s)  (Accounts s)
hasAccount
:: Login
invariantLogins
:: String [Login]  Maybe (String,String)
:: Login =
:: Login
:: Int
:: s
// login info
// unique identifier
// state
:: String
:: PasswordBox
// Should be unique
// Should remain secret
(Accounts s)  (Maybe (Account s))
46
iTasks can be used for persistent storage of information
definition module iTaskDB
import iTasks
:: DBid a
mkDBid :: String Lifespan  (DBid a)
readDB :: (DBid a)
writeDB :: (DBid a) a
 Task a
 Task a
| iData a
| iData a
47
Creating a database for a login accounts…
accountId :: DBid (Accounts a)
accountId = mkDBid "loginAccount" TxtFile
readAccountsDB :: (Task (Accounts a)) | iData a
readAccountsDB = readDB accountId
addAccountsDB :: (Account a) (Accounts a)  (Task (Accounts a)) | iData a
addAccountsDB acc accs = writeDB accountId (addAccount acc accs)
48
Creating a database for a login accounts…
accountId :: DBid (Accounts a)
accountId = mkDBid "loginAccount" Database
readAccountsDB :: (Task (Accounts a)) | iData a
readAccountsDB = readDB accountId
addAccountsDB :: (Account a) (Accounts a)  (Task (Accounts a)) | iData a
addAccountsDB acc accs = writeDB accountId (addAccount acc accs)
49
Creating a database for a login accounts…
:: Void = Void
accountId :: DBid (Accounts Void)
accountId = mkDBid "loginAccount" TxtFile
readAccountsDB :: (Task (Accounts Void))
readAccountsDB = readDB accountId
addAccountsDB :: (Account Void) (Accounts Void)  (Task (Accounts Void))
addAccountsDB acc accs = writeDB accountId (addAccount acc accs)
50
Handling login's (1)
handleLogin :: (Task (Maybe (Account Void)))
handleLogin
=
[Txt "Type in your name and password...", Br, Br]
?>> loginForm
=>> \login 
readAccountsDB
=>> \accounts 
return_V (hasAccount login accounts)
loginForm :: (Task Login)
loginForm = editTask "Done" createDefault <<@ Submit
51
Handling login's (2)
newLogin :: (Task (Account Void))
newLogin = newTask "newLogin" newLogin`
newLogin`
=
=>> \login 
=>> \accounts 
[Br, Br, Txt "Type in name and password you want to use...", Br ,Br]
?>> loginForm
readAccountsDB
case (invariantLogins "" [login:[account.login \\ account <- accounts]]) of
(Just (_,error))  [Txt error, Br, Br]
?>> newLogin
Nothing 
let
newId = length accounts
newAccount =
{ login
= login
, uniqueId = newId
, state = Void
}
in
addAccountsDB newAccount accounts
=>> \_  [Txt ("You are administrated
, your id = " <+++ newId)]
?>> buttonTask "OK" (return_V newAccount)
52
Handling login's (3)
loginProcedure :: (Task Int)
loginProcedure = newTask "loginProcedure" loginProcedure`
loginProcedure`
=
chooseTask [ ("Login",
, ("New Login",
=>> \account ->
handleLogin)
newLogin
return_V (Just account))
]
=>> \mbacc ->
-||buttonTask "Cancel" (return_V Nothing)
case mbacc of
Nothing 
[Txt "Sorry, you have to try again!",Br,Br]
?>> buttonTask "OK" loginProcedure
(Just acc) 
return_V acc.uniqueId
53
Defining a multi-user workflow system (1)
Start world = doHtmlServer (singleUserTask -1 True myAppl ) world
myAppl
=
=>> \myid 
=>> \accounts 
loginProcedure
readAccountsDB
startNewTask myid True
(assignTasks accounts <<@ TxtFile)
assignTasks accounts
= andTasks [
( acc.login.loginName
, acc.uniqueId @:: assignWork acc.login.loginName acc.uniqueId
)
\\ acc <- accounts
]
assignWork name i = …
54
Defining a multi-user workflow system (2)
assignWork ::
Bool
(Task Void)
(acc  Task acc)
((String,Int,acc)  (Task a))
 (Task [a]) | iData acc & iData
//
//
//
//
a
traceOn
welcome task
administration task
\name uniqueid admin ->
Examples:

newsgroups

marking
55
Clean

Introduction

Defining Interactive Multi-user Workflow Systems for the web





Implementation




Defining a simple task: an editor for a web form
Combinators for constructing tasks
Assigning tasks to users
Logging in to a Multi-user Workflow System
Basic idea of generic programming
Generic functions for handling web forms: i-Data
Implementation of i-Tasks
Conclusion & Future Research
56
Generic programming
Some functions are more or less the same:
equality, unification, mapping, zipping, folding,
pretty printers, parsers, generators,
GAST: automatic test system
Graphical User Interfaces
???
Define the general case once and for all
by induction on the structure of data types.
Automatically obtain a concrete function for any concrete data type !
Applicable for quite a large class of algorithms…
Exceptions make the rule !
One can define specialized instances for special types…
57
Example types
:: List a
= Nil
| Cons a (List a)
:: Rose a
= Rose a (List (Rose a))
:: Tree a b
= Tip a
| Bin b (Tree a b) (Tree a b)
58
Overloaded equality
class == infix 4 t :: t t  Bool
instance == (List a) | == a
where (==) Nil
Nil
(==) (Cons x xs) (Cons y ys)
(==) _
_
= True
= x == y && xs == ys
= False
instance == (Rose a) | == a
where (==) (Rose x xs) (Rose y ys)
(==) _
_
= x == y && xs == ys
= False
instance == (Tree a b) | == a & == b
where (==) (Tip x)
(Tip y)
= x == y
(==) (Bin x ltx rtx) (Bin y lty rty) = x == y && ltx == lty && rtx == rty
(==) _
_
= False
59
The idea of generic programming
Map_List
List a
List b
Map_Rose
Rose a
Rose b
60
The idea of generic programming
Map_List
List a
List b
Map_Generic
Generic a
Generic b
Map_Rose
Rose a
Rose b
61
The idea of generic programming
Map_List
List a
List b
fromList
toList
Map_Generic
Generic a
Generic b
fromRose
toRose
Map_Rose
Rose a
Rose b
62
Generic programming
We need a generic representation:
a way to represent any value of any type
Clean is typed: what is the type of such a representation ?
One generic type which can represent all possible types not possible:
type correctness of programs becomes undecidable
one would obtain a complete different system
Solution: use a couple of simple types to represent any type !
63
Generic type representation
Example types
:: List a
:: Rose a
:: Tree a b
= Nil | Cons a (List a)
= Rose a (List (Rose a))
= Tip a | Bin b (Tree a b) (Tree a b)
Binary sums and products (in generic prelude)
:: UNIT
= UNIT
:: PAIR a b
= PAIR a b
:: EITHER a b
= LEFT a | RIGHT b
Generic type representations
:: ListG a
:== EITHER UNIT (PAIR a (List a))
:: RoseG a
:== PAIR a (List (Rose a))
:: TreeG a b
:== EITHER a (PAIR b (PAIR (Tree a b) (Tree a b)))
64
Generic type representation
Conversions to the generic domain can be automatically generated
fromList :: (List a)  ListG a
fromList Nil
= LEFT UNIT
fromList (Cons a as)
= RIGHT (PAIR a as)
fromRose :: (Rose a)  RoseG a
fromRose (Rose a list_of_roses) = PAIR a list_of_roses
fromTree :: (Tree a b)  TreeG a b
fromTree (Tip a) = LEFT a
fromTree (Bin b leftTree rightTree) = RIGHT (PAIR b (PAIR leftTree rightTree))
65
Generic type representation
Conversions back to the user domain can be automatically generated
toList :: (ListG a)  List a
toList LEFT UNIT
toList (RIGHT (PAIR a as))
= Nil
= Cons a as
toRose :: (RoseG a)  Rose a
toRose (PAIR a list_of_roses)
= Rose a list_of_roses
toTree :: (TreeG a b)  Tree a b
toTree (LEFT a)
= Tip a
toTree (RIGHT (PAIR b (PAIR leftTree rightTree))) = Bin b leftTree rightTree
66
Generic equality
generic gEq a :: a a  Bool
gEq
gEq
gEq
gEq
gEq
{|Int|} x y
{|Char|} x y
{|Bool|} x y
{|Real|} x y
{|String|} x y
gEq {|UNIT|} UNIT UNIT
=x
=x
=x
=x
=x
== y
== y
== y
== y
== y
= True
gEq {|PAIR|} eqx eqy (PAIR x1 y1) (PAIR x2 y2) = eqx x1 x2 && eqy y1 y2
gEq {|EITHER|} eqx eqy (LEFT x) (LEFT y)
= eqx x y
gEq {|EITHER|} eqx eqy (RIGHT x) (RIGHT y) = eqy x y
gEq {|EITHER|} eqx eqy
__
= False
gEq {|MyType|} …
=
67
Clean

Introduction

Defining Interactive Multi-user Workflow Systems for the web





Implementation




Defining a simple task: an editor for a web form
Combinators for constructing tasks
Assigning tasks to users
Logging in to a Multi-user Workflow System
Basic idea of generic programming
Generic functions for handling web forms: i-Data
Implementation of i-Tasks
Conclusion & Future Research
68
editTask uses generic functions
class
class
class
class
class
class
iData a
iCreateAndPrint a
iCreate a
iPrint a
iParse a
iSpecialStore a
|
|
|
|
|
|
gForm {|*|} , iCreateAndPrint, iParse, iSpecialStore a
iCreate, iPrint a
gUpd {|*|} a
gPrint {|*|} a
gParse {|*|} a
gerda {|*|}, TC a
It requires the instantiation of several generic functions for type "a" e.g.
gForm
html form creation,
gUpd
form handling,
gParse
parsing,
gPrint
printing,
gerda
data storage I a relational database,
TC
Conversion to and from Dynamics, option used to store functions
which can all, on request, automatically be derived by the compiler !
69
Implementation architecture
v :: T
Clean Application
70
Implementation architecture
Browser
Html code
Web Server
gForm: Html code
v :: T
Clean Application
serialize: gPrint
store: gerda
File / Data Base
71
Implementation architecture
Browser
Web Server
File / Data Base
72
Implementation architecture
Browser
∆v :: T∆v
Web Server
∆v :: T∆v
gUpd: v` :: T
Clean Application
v :: T
File / Data Base
de-serialize: gParse
retrieve: gerda
73
Implementation architecture
Browser
Html code
∆v :: T∆v
Web Server
gForm: Html code
v :: T
∆v :: T∆v
gUpd: v` :: T
Clean Application
v :: T
serialize: gPrint
store: gerda
File / Data Base
de-serialize: gParse
retrieve: gerda
74
Generic functions used for i-Tasks / i-Data
The following generic functions are used:
generic gForm a :: (Init, FormId a) *HSt  *(Form a, *HSt)
can create an interactive Html form for any value of any type
generic gUpd a :: UpdMode a  (UpdMode, a)
can update a value of any type given any change made in a form
generic gPrint a :: a  String
can serialize a value of any (first-order) Clean type
to store a form state in a page, file or database
generic gParse a :: String  Maybe a
can de-serialize a value of any (first-order) Clean type
to re-construct a form state
75
Generating forms
generic gForm a :: (Init, FormId a)
:: FormId a
=
{ id
, initval
, mode
, lifespan
, storage
}
:: String
:: a
:: Mode
:: Lifespan
:: StorageFormat
*HSt  *(Form a, *HSt)
//
//
//
//
//
id *uniquely* identifying the form
initial value (Init) or new value (Set)
kind of form
where to store it, and for how long
storage format
76
Generating forms
generic gForm a :: (Init, FormId a)
*HSt  *(Form a, *HSt)
:: FormId a
=
{ id
, initval
, mode
, lifespan
, storage
}
:: String
:: a
:: Mode
:: Lifespan
:: StorageFormat
:: Init
:: Mode
:: Lifespan
:: StorageFormat
= Init | Set
= Edit | Submit | Display | NoForm
= Database | TxtFile | Session | Page | Temp
= StaticDynamic | PlainString
//
//
//
//
//
id *uniquely* identifying the form
initial value (Init) or new value (Set)
kind of form
where to store it, and for how long
storage format
77
Generating forms
generic gForm a :: (Init, FormId a)
*HSt  *(Form a, *HSt)
:: FormId a
=
{ id
, initval
, mode
, lifespan
, storage
}
:: String
:: a
:: Mode
:: Lifespan
:: StorageFormat
:: Init
:: Mode
:: Lifespan
:: StorageFormat
:: *HSt
= Init | Set
= Edit | Submit | Display | NoForm
= Database | TxtFile | Session | Page | Temp
= StaticDynamic | PlainString
// State passed around single threadedly
//
//
//
//
//
id *uniquely* identifying the form
initial value (Init) or new value (Set)
kind of form
where to store it, and for how long
storage format
78
Generating forms
generic gForm a :: (Init, FormId a)
*HSt  *(Form a, *HSt)
:: FormId a
=
{ id
, initval
, mode
, lifespan
, storage
}
:: String
:: a
:: Mode
:: Lifespan
:: StorageFormat
:: Init
:: Mode
:: Lifespan
:: StorageFormat
:: *HSt
= Init | Set
= Edit | Submit | Display | NoForm
= Database | TxtFile | Session | Page | Temp
= StaticDynamic | PlainString
// State passed around single threadedly
:: Form a
=
{ changed
, value
, form
}
:: Bool
:: a
:: [BodyTag]
//
//
//
//
//
id *uniquely* identifying the form
initial value (Init) or new value (Set)
kind of form
where to store it, and for how long
storage format
// has the user edited the form ?
// current value in data domain (feel)
// html code representing view domain (look)
79
Updating a value (1)
How can we reconstruct a value that has been changed interactively ?
We only need to know 3 things:
 Which type was it and what was its original value?
 Which parts have been changed in the original value?
»
»
»
We don't need any knowledge about the html code !
We only need to know which values have been changed
We just need the position in its generic representation
 What are the changed values ?

Simple case: only a few basic cases:
»
»

Change existing value
Create new values
: Int, Real, String, Bool, …
: When you select a constructor
Complication : change of form may depend on the change of others
80
Updating a value (2)
generic gUpd a
:: UpdMode a  (UpdMode,a)
:: UpdMode
= UpdSearch UpdValue Pos
| UpdCreate [ConsPos]
| UpdDone
:: UpdValue
= UpdI Int
| UpdR Real
| UpdB Bool
| UpdS String
| UpdC String
:: ConsPos
= ConsLeft
| ConsRight
:: Pos
// search for position
// in generic representation
// copy the remaining expression
//
//
//
//
//
new Integer value
new Real value
new Boolean value
new String value
new Constructor value
:== Int
81
Updating a value (3)
gUpd {|Int|} (UpdSearch (UpdI ni) 0) _
= (UpdDone,ni)
gUpd {|Int|} (UpdSearch val cnt)
= (UpdSearch val (cnt - 1), i)
i
gUpd {|Int|} (UpdCreate p)
gUpd {|Int|} mode
_
i
= (UpdCreate p, 0)
= (mode, i)
82
Snapshot from Clean's CD shop
83
Clean

Introduction

Defining Interactive Multi-user Workflow Systems for the web





Implementation




Defining a simple task: an editor for a web form
Combinators for constructing tasks
Assigning tasks to users
Logging in to a Multi-user Workflow System
Basic idea of generic programming
Generic functions for handling web forms: i-Data
Implementation of i-Tasks
Conclusion & Future Research
84
What do we need for iTasks ?

We need a notion of “tasks”: inactive, active, and completed

There is only one application for all users

This application starts from scratch each time information is communicated
 The web has no notion of state, we have to store all relevant information
 We have to be able to find out what we were doing -> functions + iData
 We need to invent unique id’s for a form and its corresponding state
 Careful: tasks are dynamically created, can be recursive !
 We have to find out which tasks are active and deal with them
 We have to support all options
 If active tasks are completed, we have to activate the next set of tasks
 We have to display the tasks in an understandable way
 We have to find out who has to do what, and show relevant information only
 We have to deal with multi-user aspects
 We have to gather trace information
 We have to remove unneeded administration of completed tasks
85
iTask Administration State
:: *TSt
=
{ tasknr
, activated
, userId
, currentUserId
, html
, options
, hst
, trace
}
:: [Int]
:: Bool
:: Int
:: Int
:: HtmlTree
:: Options
:: *HSt
:: Maybe [Trace]
//
//
//
//
//
//
//
//
unique form-id for every task
if assigned activate, if returned completed
id of user who has to do the task
id of current application user
accumulator for html code
iData and iTasks options
iData state
for displaying task trace
86
iTask Administration State
:: *TSt
=
{ tasknr
, activated
, userId
, currentUserId
, html
, options
, hst
, trace
}
:: HtmlTree
:: [Int]
:: Bool
:: Int
:: Int
:: HtmlTree
:: Options
:: *HSt
:: Maybe [Trace]
//
//
//
//
//
//
//
//
unique form-id for every task
if assigned activate, if returned completed
id of user who has to do the task
id of current application user
accumulator for html code
iData and iTasks options
iData state
for displaying task trace
= BT [BodyTag]
//
| (@@:) infix 0 (Int,String) HtmlTree//
| (-@:) infix 0 Int HtmlTree
//
| (+-+) infixl 1 HtmlTree HtmlTree //
| (+|+) infixl 1 HtmlTree HtmlTree //
html code
code with user id and task name
code not to display to user id
place code next to each other
place code below each other
87
iTask Administration State
:: *TSt
=
{ tasknr
, activated
, userId
, currentUserId
, html
, options
, hst
, trace
}
:: HtmlTree
:: Options
=
{ tasklife
, taskstorage
, taskmode
, gc
}
:: [Int]
:: Bool
:: Int
:: Int
:: HtmlTree
:: Options
:: *HSt
:: Maybe [Trace]
//
//
//
//
//
//
//
//
unique form-id for every task
if assigned activate, if returned completed
id of user who has to do the task
id of current application user
accumulator for html code
iData and iTasks options
iData state
for displaying task trace
= BT [BodyTag]
//
| (@@:) infix 0 (Int,String) HtmlTree//
| (-@:) infix 0 Int HtmlTree
//
| (+-+) infixl 1 HtmlTree HtmlTree //
| (+|+) infixl 1 HtmlTree HtmlTree //
:: Lifespan
:: StorageFormat
:: Mode
:: GarbageCollect
//
//
//
//
html code
code with user id and task name
code not to display to user id
place code next to each other
place code below each other
default:
default:
default:
default:
Session
PlainString
Edit
Collect
88
Activating a task (simplified)
:: Task a
:== *TSt  *(a,*TSt)
89
Activating a task (simplified)
:: Task a

:== *TSt  *(a,*TSt)
Each task is assumed to call doTask
 increment task number, such that this number is unique;
 when activated call the task, create a default value otherwise;
 when a task is finished, activate is returned True, False otherwise.
90
Activating a task (simplified)
:: Task a

:== *TSt  *(a,*TSt)
Each task is assumed to call doTask
 increment task number, such that this number is unique;
 when activated call the task, create a default value otherwise;
 when a task is finished, activate is returned True, False otherwise.
doTask :: String (Task a)  (Task a) | iCreateAndPrint a
doTask taskname thistask = mkTaskNoInc taskname thistask o incTaskNr
where
mkTaskNoInc taskname thistask tst=:{activated, tasknr, options}
| not activated
= (createDefault, tst)
# (val,tst)
= thistask tst
= (val, {tst & tasknr = tasknr, options = options})
incTaskNr tst
where
incNr []
incNr [i:is]
= {tst & tasknr = incNr tst.tasknr}
= [0]
= [i+1:is]
91
The bind is now easy... a standard bind can be used
(=>>) infix 1 :: (Task a) (a  Task b)  Task b
(=>>) taska taskb = bind
where
bind tst
# (a, tst)
= taska tst
= taskb a tst
(#>>) infix 1 :: (Task a) (Task b)  Task b
(#>>) taska taskb = bind
where
bind tst
# (_, tst)
= taska tst
= taskb tst
92
A simple combinator: ?>>
(?>>) infix 5 :: [BodyTag] (Task a) -> (Task a) | iCreate a
(?>>) prompt thistask = myTask
where
myTask tst=:{html, activated}
| not activated
= (createDefault, tst)
# (a, tst=:{activated, html = nhtml})
= thistask {tst & html = BT []}
| activated
= (a, {tst & html = html})
= (a, {tst & html = html +|+ BT prompt +|+ nhtml})
93
A simple combinator: -&&(-&&-) infixr 4 :: (Task a) (Task b)  (Task (a,b)) | iCreateAndPrint a & iCreateAndPrint b
(-&&-) taska taskb = mkTask "-&&-" (doAndTask (taska, taskb))
doAndTask (taska, taskb) tst=:{tasknr, html}
# (a, tst=:{activated = adone, html = ahtml})
= mkParSubTask "andTask" 0 taska {tst & html = BT []}
# (b, tst=:{activated = bdone, html = bhtml})
= mkParSubTask "andTask" 1 taskb {tst & tasknr = tasknr, html = BT []}
= ((a,b), {tst & activated = adone && bdone, html = html +|+ ahtml +|+ bhtml})
94
A simple combinator: -&&(-&&-) infixr 4 :: (Task a) (Task b)  (Task (a,b)) | iCreateAndPrint a & iCreateAndPrint b
(-&&-) taska taskb = mkTask "-&&-" (doAndTask (taska, taskb))
doAndTask (taska, taskb) tst=:{tasknr, html}
# (a, tst=:{activated = adone, html = ahtml})
= mkParSubTask "andTask" 0 taska {tst & html = BT []}
# (b, tst=:{activated = bdone, html = bhtml})
= mkParSubTask "andTask" 1 taskb {tst & tasknr = tasknr, html = BT []}
= ((a,b), {tst & activated = adone && bdone, html = html +|+ ahtml +|+ bhtml})
mkParSubTask name i task tst = task (newSubTaskNr (setActivated (subTaskNr i tst)))
subTaskNr
newSubTaskNr
setActivated
i tst
tst
tst
= { tst & tasknr = [ i : tst.tasknr] }
= { tst & tasknr = [-1 : tst.tasknr] }
= { tst & activated = True }
95
Clean

Introduction

Defining Interactive Multi-user Workflow Systems for the web





Implementation




Defining a simple task: an editor for a web form
Combinators for constructing tasks
Assigning tasks to users
Logging in to a Multi-user Workflow System
Basic idea of generic programming
Generic functions for handling web forms: i-Data
Implementation of i-Tasks
Conclusion & Future Research
96
Conclusions

Compact specification, many details are handled automatically
 very intuitive

All "standard" workflows patterns offered
 but we are lacking a graphical editor...

Offers a lot of additional expressive power
 Typed
 Workflows are dynamically generated
 Additional Workflow Patterns: lazy send / receive, -!>
 Higher Order Workflows
 Highly re-usable code

First industrial real-world application has been made
(Car Damage Negotiation System, ABZ)
97
Future Work

Show applicability via more, large real world applications

Combine with Client site evaluation
 Fast Clean interpreter (Jan-Martin Jansen) running in browser
 add “Ajax” technology

Integrate with main stream web development tools (Dreamweaver)

Improve performance






Practical issues: What is the ideal set of combinators ?
Can we exploit lazy evaluation ?
Theoretical issues: What is the minimal set of combinators ?
How does it compare with other approaches: Petri Nets, Process Algebra, μCRL ?
Can we prove properties of a workflow system ?
What kind of static properties can we analyse ?
98