When we design and implement a graphical user interface, we have to take two aspects into account: the static aspect, which specifies its appearance (which buttons to place where, what menus to display, etc.), and the dynamic aspect, which specifies its behaviour in reaction to the user's actions. The two can be interlinked: as a reaction to the user's action, the graphical user interface may change its appearance.
In HTK, these two aspects are modelled by monads. The static aspect is modelled in the IO monad, where all of Haskell's external interactions takes place. The dynamic aspect is modelled by events. For a more complete description of events, we refer to , but for the time being, events are an abstract datatype with three main operations:
sync :: Event a-> IO awhich holds the current thread until an event of type Event a occurs. The basic events will be user interactions, such as clicking a button; more complex events can be built using the following operators.
(>>>=) :: Event a-> (a-> IO b)-> Event b (>>>) :: Event a-> IO b-> Event battaches an IO action to an event; if we synchronize on this event, the IO action will be performed after the event occurs.
always :: IO a-> Event a
That the dynamic behaviour is not modelled with IO actions directly reflects the fact that user interaction in a graphical user interface is different from other forms of I/O, because it happens asynchronously.
Further, events allow the user interface to be concurrent in a natural and controlled way, leading to a reasonable and still tractable degree of concurrency; the function
spawnEvent :: Event () -> IO (IO ())spawns a concurrent thread which syncronises on the given event. The IO action returned kills the concurrent thread.