Haskell in web browser/Haskell web toolkit
Haskell Web Toolkit (further referred to as HsWTK) is a thin layer built on top of DOM interfaces. It provides program interfaces to compose static layout of a web application page, and to hook up visual elements of an application to event handlers and XML HTTP communication means. HsWTK hides the low-level DOM APIs where possible; however their knowledge may be necessary to develop certain types of visual components and event handlers.
To build a web-based GUI, HsWTK defines the following type:
type Widget = THTMLDocument -> THTMLElement -> Bool
That is, Widget is a function, or, to be a more precise, an action (as evaluation of this function does assume side effects). This action's first argument, of type THTMLDocument, refers to the HTML document containing the GUI elements. The action's second argument, of type THTMLElement, refers to a parent HTML element. This makes perfect sense from the DOM standpoint, as in order to create a visible element on a Web page, it is at least necessary to create an element by calling
Document.createElement method (which needs a Document), and next to insert the newly created element into some (parent) node by calling
HTML elements as widgets
So, inside the Widget action, some work may be done to create a HTML element, and make it a child of some other Widget. This is generalized by HsWTK as Element Creation Function, and defined as
type ECRF n = (THTMLDocument -> CPS Bool n)
Now, if we refer to Maker functions defined for HTML-tagged Elements we may see some similarity:
mkDiv :: CHTMLDocument a => a -> CPS c THTMLDivElement
If we substitute n in ECRF definition with THTMLDivElement, and remember that THTMLDocument is an instance of CHTMLDocument, we get a perfect match. From this, it may be concluded that Maker functions may serve as Element creation functions.
The simpliest form of Widget is passive widget. Passive widgets only display themselves as part of Web GUI, but are not capable of nesting other widgets. A good example of such passive widget is text label or non-clickable image.
HsWTK defines a function
passive which given an Element Creation Function, returns a Widget:
passive :: CNode n => ECRF n -> Widget
Thus, given a Maker function (e. g. mkImg), applying passive to it creates an image which will appear in the proper place of a Web page.
For a text element itself, there is a Maker function mkText which produces a text node to be inserted into a < DIV > or < SPAN > or any other element with closing tag. mkText is not a pure Maker function though; due to its type signature,
flip has to be applied to it.
One important passive widget not based on a HTML element is
nowidget. It may be used as a placeholder for any passive widget, and does not produce any kind of effects.
HTML elements with closing tags contain other elements in between. To reflect this, HsWTK defines another function,
container. This function, applied to a Maker function, produces a widget capable of nesting other widgets.
For the purpose of sequencing widgets within a container, or nesting widgets in containers, HsWTK defines combinators
++|. Please refer to the appropriate section of the Graphics.UI.HsWTK module documentation.
+++ combinator sequences two widgets inside a container. Widgets (
a +++ b) appear second (b) at the right of the first (a). Result of such composition is also a widget, and it may be sequenced with other widgets.
(a +++ b) +++ c is same as
a +++ b +++ c.
<< combinator nests a widget (or composition of widgets) in a container.
So, the following fragment of code creates a widget consisting of a < DIV > with a text inside:
mkTextFl = flip mkText container mkDiv << passive (mkTextFl "Hello World")
To simplity the code, HsWTK defines these two functions:
textPwhich is equivalent to
passive (flip mkText txt)
|<<which is defined as
c |<< d = container c << d, that is the word
containermay be omitted.
The toplevel widget (one that is not nested in any other widget) has to be inserted into the HTML document body. This is acieved by applying the function
docBodyC to the toplevel widget. This application often becomes the
main function of a Web application. Please note that document body is not a Widget.
Code example - Hello Web
At this point, we are able to code our first HsWTK example. By tradition, this is a Hello ... program. Paste the code below into Yhc Web Service New Entry Form and press the Submit button (don't forget to fill out the Author and Title field).
-- Begin Pasteable Code -- module HelloWebHsWTK where import DOM.Level2.HTMLSpanElement import Graphics.UI.HsWTK -- The Main Function main = docBodyC mainW -- The Toplevel Widget mainW = (mkSpan |<< textP "Hello " +++ textP "Web") -- End Pasteable Code --
After the compilation is finished, load the generated Web page. Haskell says Hello to the new environment it just has started to explore.
The example shows all the facilities of HasWTK we recently discussed:
- widgets sequencing (+++ combines two text elements one after another)
- creation of a HTML Element based widget (mkSpan)
- nesting composition of widgets in a container (|<<)
- inserting the toplevel widget into the document body (docBodyC)