Introduction to Functional Programming – Haste: Running Haskell in the Browser | TDA555 / DIT440, LP1, HT2013 |
Home | Schedule | Labs | Exercises | Exam | About | Fire | Forum | TimeEdit | Links | 2012 |
Links:
IntroductionHaste is a compiler from Haskell to Javascript, which is a common language for programming interactive web pages. Using Haste it is possible to use Haskell to specify the behavior of web pages. But before we can talk about the interactive behavior of web pages, we need to know how to express the content of web pages.The main language for specifying the content of web pages is HTML. An example HTML document is the following: <!DOCTYPE html> <html> <body> <h1>My web page</h1> This document has a heading and some text. <em>This sentence is emphasized.</em> </body> </html>When loading this document in a browser, a page like the following will be displayed: My web pageThis document has a heading and some text. This sentence is emphasized.
HTML documents are structured using tags, which usually come in pairs; e.g. Note that the browser does not display the HTML tags, but uses the tags to interpret the content of the page. The following tags are useful when creating simple web pages: In addition, the<br/> tag specifies a newline. It is an unpaired tag that does not have a corresponding closing tag.
Interactive web pagesTo create pages that react to user input one can make use of buttons (<button> ) and text entries (<input> ). Here is a simple example of a text entry with a button below:
<input type="text" size="30" id="answer" value="Type your answer here..."></input> <br/> <button id="submit">Submit answer</button>This example will be displayed as follows in the browser: id="answer" and id="submit" ) is to make it possible to refer to these elements from scripting code. For example, a script may be set to wait for a click on the Submit button. Once a click is received, it may read the contents of the text entry, and perhaps update some other part of the page depending on the submitted answer.
In order to add an identifier to a piece of text (e.g. so that it can be updated by a script), use a <span id="some-identifyer"> ... </span>
To attach a script (typically Javascript) to a web page, use the <html> <head> <script src="script.js" type="text/javascript">...</script> </head> <body> ... </body> </html>This will use the Javascript program script.js to control the content of the page.
In this course, we will not need to know anything about Javascript. We will simply use Haste to compile Haskell code to Javascript, and then use a Scripting using Haste
First make sure that you have installed Haste.
Haste is capable of compiling arbitrary Haskell code to Javascript. However, in order to use Haste for scripting web pages, one has to make use of its built-in library:
HelloWorld.hs is a simple example of a Haste script that opens a small dialogue window as soon as the page is loaded: main :: IO () main = alert "Hello world!"To compile a Haskell file such as HelloWorld.hs into Javascript, run the following command in the terminal: > hastec HelloWorld.hs Connecting to the documentTo connect a script to elements in the document, useelemById , e.g. as such:
Just inp <- elemById "user-input" Just outp <- elemById "script-output"The above will retrieve the elements identified by "user-input" and "script-output" respectively. These variables can then be used, e.g. to read from the input element
text <- getProp inp "value"and to write this text to an output element setProp outp "innerHTML" textThe example Echo.hs demonstrates this kind of reading and writing. Here, the interactive code is put inside a "callback": onEvent inp OnKeyUp $ \_ -> do text <- getProp inp "value" setProp outp "innerHTML" textThis will cause the do block to be re-run whenever the user releases a key in the text entry identified by inp .
Calculator.hs is a similar example, but where the script actually computes a result, rather than just copying text. Graphics in the browserThe HTML5 standard includes a tag<canvas> for drawing figures in the browser. For example, to include a 300x300 pixels drawing area in a document, simply include
<canvas id="canvas" style="border: 1px solid black;" width="300" height="300"></canvas>somewhere in the body of the document. In order to interface with the canvas from the Haskell code, one first has to import Haste's canvas library import Haste.Graphics.CanvasTo see the contents of this library, have a look at its source code.
This library contains two monads used for drawing: line :: Point -> Point -> Shape () rect :: Point -> Point -> Shape () circle :: Point -> Double -> Shape ()A Point is a pair of floating point numbers corresponding to the number of pixels in the x- and y-dimension, respectively:
type Point = (Double,Double) Combining picturesShapes can be combined using do-notation:snowMan :: Double -> Shape () snowMan x = do circle (x,100) 20 circle (x,65) 15 circle (x,40) 10A Shape can be turned into a picture in two basic ways:
fill :: Shape () -> Picture () stroke :: Shape () -> Picture ()The former function fills the shape with solid color, while the latter only draws the contours. Pictures are also combined using do-notation: twoSnowMenInABox :: Picture () twoSnowMenInABox = do fill $ snowMan 100 stroke $ snowMan 200 stroke $ rect (50,10) (250,150)This will result in the following picture:
![]() (The lines on the right-hand side of the snow men are probably due to a bug (reported).) To actually draw the above picture on the canvas, we can use the following main definition: main :: IO () main = do Just can <- getCanvasById "canvas" render can twoSnowMenInABoxSee Snowmen.hs . AnimationsIt is possible to animate pictures in a canvas simply by periodically updating the picture. FallingBall.hs is a simple animation of a falling ball. Here, the animation is achieved by the functionfall recursively calling itself after a time-out of 20 milliseconds. The y argument of fall acts as the state of the animation; by multiplying y in the recursive call, a slightly different picture is drawn in each iteration.
Finally BouncingBalls.hs is a more advanced animation, where the state is updated interactively by clicking in the canvas using the mouse. For this, an IO reference is used to hold the current state. Learn more about references here: Data.IORef. TroubleshootingIf you get strange errors from Haste, e.g. complaining about missing files, you may want to check the following:
|