packages feed

elerea-examples 1.2.0 → 2.0.0

raw patch · 13 files changed

+160/−112 lines, 13 filesdep ~elerea

Dependency ranges changed: elerea

Files

README view
@@ -1,23 +1,23 @@-This package provides some simple examples in order to help getting-started with the Elerea FRP library. Check out the doc directory for-the colourful literate sources of the Chase and Breakout examples. All-the executables created start with the elerea- prefix.+Example applications for Elerea. They are factored out into their+own package so as to avoid unnecessary dependencies in the+library. Check out the @doc@ directory for the colourful literate+sources.  The programs included are the following: -  * Chase: a minimal example that demonstrates reactivity and mutually-    recursive signals; you can give a thrust to the square following-    the mouse with a left click.+* bounce (current): an example for creating dynamic collections of+  signals with the experimental interface; left click to create+  balls, drag existing balls with left button to propel them and+  drag with right to select balls for deletion (upon release) -  * Breakout: a not too fancy breakout clone that also demonstrates-    Graphviz output; you can get an SVG rendition of the signal-    structure with the following command if Graphviz is installed:+* chase (legacy): a minimal example that demonstrates reactivity and+  mutually recursive signals -    elerea-breakout --dump-dot | dot -Tsvg -o breakout.svg+* breakout (legacy): a not too fancy breakout clone that also+  demonstrates Graphviz output; you can get an SVG rendition of the+  signal structure with the following command if Graphviz is+  installed: -    You can simply use the mouse to move the paddle.+  elerea-breakout --dump-dot | dot -Tsvg -o breakout.svg -  * Bounce: an example for creating dynamic collections of signals-    with the experimental interface; left click to create balls, drag-    existing balls with left button to propel them and drag with right-    to select balls for deletion (upon release)+  You can simply use the mouse to move the paddle.
doc/Breakout.html view
@@ -1,6 +1,5 @@ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><title></title><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><meta name="generator" content="pandoc" /><link rel="stylesheet" href="hscolour.css" type="text/css" media="all" />-</head><body><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">-<html><head><!-- Generated by HsColour, http://www.cs.york.ac.uk/fp/darcs/hscolour/ --><title>Haskell code</title> <link type='text/css' rel='stylesheet' href='hscolour.css' /> </head><body><div id="elerea-breakout-example"><h1>Elerea Breakout example</h1><p>Breakout is one of the simplest test applications that brings up some problems with non-trivial solutions. In particular, there is a circular dependency between the position and the velocity of the ball. The position is the integral of the velocity, while velocity can have instantaneous changes due to collisions, which is a function of the position of the ball and the current state of the field. The field is dynamic, and it also forms a mutual dependency loop with the ball position. On top of these, part of the field (at least if we regard the paddle as part of it) depends on user input, and its effects start propagating in the game state as soon as the ball reaches the level of the paddle.</p><p>Elerea lets us express all these circular dependencies in a natural way, by simply referring to the respective signals by their names. User input is also seen as a signal from inside the reactive part, while the imperative framework is given a sink fuction to update it as needed. Type safety is ensured all the way.</p><img src="Breakout.png" alt="Elerea Breakout in action" /><p>You can also have the program output the signal structure in <a href="http://www.graphviz.org/">Graphviz</a> dot format with the <code>--dump-dot</code> switch after the game is over. For instance, if Graphviz is installed, you can get an SVG rendition of the graph using the following command:</p><p><code>elerea-breakout --dump-dot | dot -Tsvg -o breakout.svg</code></p><p>Below follows the full source of the example.</p><pre><span class='hs-varop'>&gt;</span> <span class='hs-comment'>{-# LANGUAGE RecursiveDo #-}</span>+</head><body><h1 id="elerea-breakout-example">Elerea Breakout example</h1><p>Breakout is one of the simplest test applications that brings up some problems with non-trivial solutions. In particular, there is a circular dependency between the position and the velocity of the ball. The position is the integral of the velocity, while velocity can have instantaneous changes due to collisions, which is a function of the position of the ball and the current state of the field. The field is dynamic, and it also forms a mutual dependency loop with the ball position. On top of these, part of the field (at least if we regard the paddle as part of it) depends on user input, and its effects start propagating in the game state as soon as the ball reaches the level of the paddle.</p><p>Elerea lets us express all these circular dependencies in a natural way, by simply referring to the respective signals by their names. User input is also seen as a signal from inside the reactive part, while the imperative framework is given a sink fuction to update it as needed. Type safety is ensured all the way.</p><img src="Breakout.png" alt="Elerea Breakout in action" /><p>You can also have the program output the signal structure in <a href="http://www.graphviz.org/">Graphviz</a> dot format with the <code>--dump-dot</code> switch after the game is over. For instance, if Graphviz is installed, you can get an SVG rendition of the graph using the following command:</p><p><code>elerea-breakout --dump-dot | dot -Tsvg -o breakout.svg</code></p><p>Below follows the full source of the example.</p><pre><span class='hs-varop'>&gt;</span> <span class='hs-comment'>{-# LANGUAGE RecursiveDo #-}</span> <span class='hs-varop'>&gt;</span> <span class='hs-varop'>&gt;</span> <span class='hs-keyword'>module</span> <span class='hs-conid'>Main</span> <span class='hs-keyword'>where</span> <span class='hs-varop'>&gt;</span> @@ -20,7 +19,7 @@ </pre> <pre><span class='hs-varop'>&gt;</span> <span class='hs-keyword'>import</span> <span class='hs-conid'>Common</span><span class='hs-varop'>.</span><span class='hs-conid'>Utils</span> <span class='hs-varop'>&gt;</span> <span class='hs-keyword'>import</span> <span class='hs-conid'>Common</span><span class='hs-varop'>.</span><span class='hs-conid'>Vector</span>-</pre><div id="global-constants"><h2>Global constants</h2><p>The dimensions of the ball, which behaves as a rectangle in collision detection, but is drawn as an ellipse.</p><pre><span class='hs-varop'>&gt;</span> <span class='hs-varid'>ballW</span> <span class='hs-keyglyph'>=</span> <span class='hs-num'>0.04</span>+</pre><h2 id="global-constants">Global constants</h2><p>The dimensions of the ball, which behaves as a rectangle in collision detection, but is drawn as an ellipse.</p><pre><span class='hs-varop'>&gt;</span> <span class='hs-varid'>ballW</span> <span class='hs-keyglyph'>=</span> <span class='hs-num'>0.04</span> <span class='hs-varop'>&gt;</span> <span class='hs-varid'>ballH</span> <span class='hs-keyglyph'>=</span> <span class='hs-num'>0.04</span> </pre><p>The initial position and velocity of the ball.</p><pre><span class='hs-varop'>&gt;</span> <span class='hs-varid'>ballPos0</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>V</span> <span class='hs-num'>0</span> <span class='hs-layout'>(</span><span class='hs-comment'>-</span><span class='hs-num'>0.4</span><span class='hs-layout'>)</span> <span class='hs-varop'>&gt;</span> <span class='hs-varid'>ballVel0</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>V</span> <span class='hs-layout'>(</span><span class='hs-comment'>-</span><span class='hs-num'>0.4</span><span class='hs-layout'>)</span> <span class='hs-layout'>(</span><span class='hs-num'>0.35</span><span class='hs-layout'>)</span>@@ -31,14 +30,14 @@ <span class='hs-varop'>&gt;</span> <span class='hs-varid'>fieldH</span> <span class='hs-keyglyph'>=</span> <span class='hs-num'>0.5</span> </pre><p>The dimensions of each brick.</p><pre><span class='hs-varop'>&gt;</span> <span class='hs-varid'>brickW</span> <span class='hs-keyglyph'>=</span> <span class='hs-num'>0.05</span> <span class='hs-varop'>&gt;</span> <span class='hs-varid'>brickH</span> <span class='hs-keyglyph'>=</span> <span class='hs-num'>0.03</span>-</pre><p>The data structure describing the state of each brick. A brick can either be alive or dying. Dying bricks also keep track of their fadeout level.</p><pre><span class='hs-varop'>&gt;</span> <span class='hs-keyword'>data</span> <span class='hs-conid'>BrickState</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>Live</span> <span class='hs-keyglyph'>|</span> <span class='hs-conid'>Dying</span> <span class='hs-varop'>!</span><span class='hs-conid'>GLfloat</span> <span class='hs-keyword'>deriving</span> <span class='hs-layout'>(</span><span class='hs-conid'>Eq</span><span class='hs-layout'>,</span><span class='hs-conid'>Show</span><span class='hs-layout'>)</span>+</pre><p>The data structure describing the state of each brick. A brick can either be alive or dying. Dying bricks also keep track of their fadeout level.</p><pre><span class='hs-varop'>&gt;</span> <span class='hs-keyword'>data</span> <span class='hs-conid'>BrickState</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>Live</span> <span class='hs-keyglyph'>|</span> <span class='hs-conid'>Dying</span> <span class='hs-varop'>!</span><span class='hs-conid'>Double</span> <span class='hs-keyword'>deriving</span> <span class='hs-layout'>(</span><span class='hs-conid'>Eq</span><span class='hs-layout'>,</span><span class='hs-conid'>Show</span><span class='hs-layout'>)</span> </pre><p>The starting positions of the bricks.</p><pre><span class='hs-varop'>&gt;</span> <span class='hs-varid'>brickPos0</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>distributeBricks</span> <span class='hs-layout'>(</span><span class='hs-comment'>-</span><span class='hs-num'>0.7</span><span class='hs-layout'>)</span> <span class='hs-layout'>(</span><span class='hs-comment'>-</span><span class='hs-num'>0.1</span><span class='hs-layout'>)</span> <span class='hs-layout'>(</span><span class='hs-num'>0.7</span><span class='hs-layout'>)</span> <span class='hs-layout'>(</span><span class='hs-num'>0.4</span><span class='hs-layout'>)</span> <span class='hs-num'>18</span> <span class='hs-num'>10</span> <span class='hs-varop'>&gt;</span>     <span class='hs-keyword'>where</span> <span class='hs-varid'>distributeBricks</span> <span class='hs-varid'>xmin</span> <span class='hs-varid'>ymin</span> <span class='hs-varid'>xmax</span> <span class='hs-varid'>ymax</span> <span class='hs-varid'>xn</span> <span class='hs-varid'>yn</span> <span class='hs-keyglyph'>=</span> <span class='hs-keyglyph'>[</span><span class='hs-layout'>(</span><span class='hs-varid'>xmin</span><span class='hs-varop'>+</span><span class='hs-varid'>xstep</span><span class='hs-varop'>*</span><span class='hs-varid'>x</span><span class='hs-layout'>,</span><span class='hs-varid'>ymin</span><span class='hs-varop'>+</span><span class='hs-varid'>ystep</span><span class='hs-varop'>*</span><span class='hs-varid'>y</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>|</span> <span class='hs-varop'>&gt;</span>                                                         <span class='hs-varid'>x</span> <span class='hs-keyglyph'>&larr;</span> <span class='hs-keyglyph'>[</span><span class='hs-num'>0</span><span class='hs-keyglyph'>..</span><span class='hs-varid'>xn</span><span class='hs-comment'>-</span><span class='hs-num'>1</span><span class='hs-keyglyph'>]</span><span class='hs-layout'>,</span> <span class='hs-varid'>y</span> <span class='hs-keyglyph'>&larr;</span> <span class='hs-keyglyph'>[</span><span class='hs-num'>0</span><span class='hs-keyglyph'>..</span><span class='hs-varid'>yn</span><span class='hs-comment'>-</span><span class='hs-num'>1</span><span class='hs-keyglyph'>]</span><span class='hs-keyglyph'>]</span> <span class='hs-varop'>&gt;</span>               <span class='hs-keyword'>where</span> <span class='hs-varid'>xstep</span> <span class='hs-keyglyph'>=</span> <span class='hs-layout'>(</span><span class='hs-varid'>xmax</span><span class='hs-comment'>-</span><span class='hs-varid'>xmin</span><span class='hs-comment'>-</span><span class='hs-varid'>xn</span><span class='hs-varop'>*</span><span class='hs-varid'>brickW</span><span class='hs-layout'>)</span><span class='hs-varop'>/</span><span class='hs-layout'>(</span><span class='hs-varid'>xn</span><span class='hs-comment'>-</span><span class='hs-num'>1</span><span class='hs-layout'>)</span><span class='hs-varop'>+</span><span class='hs-varid'>brickW</span> <span class='hs-varop'>&gt;</span>                     <span class='hs-varid'>ystep</span> <span class='hs-keyglyph'>=</span> <span class='hs-layout'>(</span><span class='hs-varid'>ymax</span><span class='hs-comment'>-</span><span class='hs-varid'>ymin</span><span class='hs-comment'>-</span><span class='hs-varid'>yn</span><span class='hs-varop'>*</span><span class='hs-varid'>brickH</span><span class='hs-layout'>)</span><span class='hs-varop'>/</span><span class='hs-layout'>(</span><span class='hs-varid'>yn</span><span class='hs-comment'>-</span><span class='hs-num'>1</span><span class='hs-layout'>)</span><span class='hs-varop'>+</span><span class='hs-varid'>brickH</span> </pre><p>The rate at which a brick fades out. The reciprocal of this value gives the fadeout time in seconds.</p><pre><span class='hs-varop'>&gt;</span> <span class='hs-varid'>brickFade</span> <span class='hs-keyglyph'>=</span> <span class='hs-num'>0.5</span>-</pre></div><div id="game-logic"><h2>Game logic</h2><p>The entry point performs some lightweight initialisation, and defines the two user-driven signals: window size and mouse position. The <code>external</code> function creates the signal and the corresponding sink at the same time.</p><p>When all is done <code>driveNetwork</code> is invoked. It is not a library function, but part of the tiny <code>Utils</code> module .</p><pre><span class='hs-varop'>&gt;</span> <span class='hs-varid'>main</span> <span class='hs-keyglyph'>=</span> <span class='hs-keyword'>do</span>+</pre><h2 id="game-logic">Game logic</h2><p>The entry point performs some lightweight initialisation, and defines the two user-driven signals: window size and mouse position. The <code>external</code> function creates the signal and the corresponding sink at the same time.</p><p>When all is done <code>driveNetwork</code> is invoked. It is not a library function, but part of the tiny <code>Utils</code> module .</p><pre><span class='hs-varop'>&gt;</span> <span class='hs-varid'>main</span> <span class='hs-keyglyph'>=</span> <span class='hs-keyword'>do</span> <span class='hs-varop'>&gt;</span>   <span class='hs-comment'>-- Creating a window without a depth buffer</span> <span class='hs-varop'>&gt;</span>   <span class='hs-varid'>initialize</span> <span class='hs-varop'>&gt;</span>   <span class='hs-varid'>openWindow</span> <span class='hs-layout'>(</span><span class='hs-conid'>Size</span> <span class='hs-num'>640</span> <span class='hs-num'>480</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>[</span><span class='hs-conid'>DisplayRGBBits</span> <span class='hs-num'>8</span> <span class='hs-num'>8</span> <span class='hs-num'>8</span><span class='hs-layout'>,</span> <span class='hs-conid'>DisplayAlphaBits</span> <span class='hs-num'>8</span><span class='hs-keyglyph'>]</span> <span class='hs-conid'>Window</span>@@ -149,7 +148,7 @@ <span class='hs-varop'>&gt;</span> <span class='hs-varop'>&gt;</span>   <span class='hs-varid'>flush</span> <span class='hs-varop'>&gt;</span>   <span class='hs-varid'>swapBuffers</span>-</pre></div><div id="backend"><h2>Backend</h2><p>The <code>readInput</code> function has two responsibilities: it provides input for the <code>mousePosition</code> peripheral signal through its associated sink, and also feeds the time difference between two states into the system, deciding when to exit altogether (by returning <code>Nothing</code> instead of the current <code>dt</code> value wrapped in <code>Just</code>).</p><p>The <code>threadDelay</code> call at the beginning is just a trick to give the scheduler a breath. It will cause a wait equal to a scheduler tick, which is 20ms by default. The program can run perfectly without it, but it eats up all the free CPU to produce an unnecessarily high frame rate.</p><pre><span class='hs-varop'>&gt;</span> <span class='hs-varid'>readInput</span> <span class='hs-varid'>mousePos</span> <span class='hs-varid'>closed</span> <span class='hs-keyglyph'>=</span> <span class='hs-keyword'>do</span>+</pre><h2 id="backend">Backend</h2><p>The <code>readInput</code> function has two responsibilities: it provides input for the <code>mousePosition</code> peripheral signal through its associated sink, and also feeds the time difference between two states into the system, deciding when to exit altogether (by returning <code>Nothing</code> instead of the current <code>dt</code> value wrapped in <code>Just</code>).</p><p>The <code>threadDelay</code> call at the beginning is just a trick to give the scheduler a breath. It will cause a wait equal to a scheduler tick, which is 20ms by default. The program can run perfectly without it, but it eats up all the free CPU to produce an unnecessarily high frame rate.</p><pre><span class='hs-varop'>&gt;</span> <span class='hs-varid'>readInput</span> <span class='hs-varid'>mousePos</span> <span class='hs-varid'>closed</span> <span class='hs-keyglyph'>=</span> <span class='hs-keyword'>do</span> <span class='hs-varop'>&gt;</span>   <span class='hs-varid'>threadDelay</span> <span class='hs-num'>0</span> <span class='hs-varop'>&gt;</span>   <span class='hs-varid'>t</span> <span class='hs-keyglyph'>&larr;</span> <span class='hs-varid'>get</span> <span class='hs-conid'>GLFW</span><span class='hs-varop'>.</span><span class='hs-varid'>time</span> <span class='hs-varop'>&gt;</span>   <span class='hs-conid'>GLFW</span><span class='hs-varop'>.</span><span class='hs-varid'>time</span> <span class='hs-varop'>$=</span> <span class='hs-num'>0</span>@@ -173,7 +172,7 @@ <span class='hs-varop'>&gt;</span>   <span class='hs-varid'>scale</span> <span class='hs-num'>1</span> <span class='hs-layout'>(</span><span class='hs-varid'>fromIntegral</span> <span class='hs-varid'>w</span><span class='hs-varop'>/</span><span class='hs-varid'>fromIntegral</span> <span class='hs-varid'>h</span><span class='hs-layout'>)</span> <span class='hs-layout'>(</span><span class='hs-num'>1</span> <span class='hs-keyglyph'>::</span> <span class='hs-conid'>GLfloat</span><span class='hs-layout'>)</span> <span class='hs-varop'>&gt;</span>   <span class='hs-varop'>&gt;</span>   <span class='hs-varid'>matrixMode</span> <span class='hs-varop'>$=</span> <span class='hs-conid'>Modelview</span> <span class='hs-num'>0</span>-</pre></div></div><div id="utils-module"><h1>Utils module</h1><p>This module contains some functions that might make it into the core library eventually.</p><pre><span class='hs-varop'>&gt;</span> <span class='hs-keyword'>module</span> <span class='hs-conid'>Common</span><span class='hs-varop'>.</span><span class='hs-conid'>Utils</span> <span class='hs-keyword'>where</span>+</pre><h1 id="utils-module">Utils module</h1><p>This module contains some functions that might make it into the core library eventually.</p><pre><span class='hs-varop'>&gt;</span> <span class='hs-keyword'>module</span> <span class='hs-conid'>Common</span><span class='hs-varop'>.</span><span class='hs-conid'>Utils</span> <span class='hs-keyword'>where</span> <span class='hs-varop'>&gt;</span> <span class='hs-varop'>&gt;</span> <span class='hs-keyword'>import</span> <span class='hs-conid'>Control</span><span class='hs-varop'>.</span><span class='hs-conid'>Applicative</span> <span class='hs-varop'>&gt;</span> <span class='hs-keyword'>import</span> <span class='hs-conid'>Control</span><span class='hs-varop'>.</span><span class='hs-conid'>Monad</span>@@ -188,15 +187,14 @@ <span class='hs-varop'>&gt;</span>     <span class='hs-conid'>Nothing</span> <span class='hs-keyglyph'>&rarr;</span> <span class='hs-varid'>return</span> <span class='hs-conid'>()</span> </pre><p>A scalar integral function for <code>Fractional</code> instances.</p><pre><span class='hs-varop'>&gt;</span> <span class='hs-varid'>integral</span> <span class='hs-varid'>v0</span> <span class='hs-varid'>s</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>transfer</span> <span class='hs-varid'>v0</span> <span class='hs-layout'>(</span><span class='hs-keyglyph'>\</span><span class='hs-varid'>dt</span> <span class='hs-varid'>v</span> <span class='hs-varid'>v0</span> <span class='hs-keyglyph'>&rarr;</span> <span class='hs-varid'>v0</span><span class='hs-varop'>+</span><span class='hs-varid'>v</span><span class='hs-varop'>*</span><span class='hs-varid'>realToFrac</span> <span class='hs-varid'>dt</span><span class='hs-layout'>)</span> <span class='hs-varid'>s</span> </pre><p>An integral function for two-dimensional vectors defined in the <code>Vector</code> module.</p><pre><span class='hs-varop'>&gt;</span> <span class='hs-varid'>integralVec</span> <span class='hs-varid'>v0</span> <span class='hs-varid'>s</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>transfer</span> <span class='hs-varid'>v0</span> <span class='hs-layout'>(</span><span class='hs-keyglyph'>\</span><span class='hs-varid'>dt</span> <span class='hs-varid'>v</span> <span class='hs-varid'>v0</span> <span class='hs-keyglyph'>&rarr;</span> <span class='hs-varid'>v0</span><span class='hs-varop'>^+^</span><span class='hs-layout'>(</span><span class='hs-varid'>v</span><span class='hs-varop'>^*.</span><span class='hs-varid'>realToFrac</span> <span class='hs-varid'>dt</span><span class='hs-layout'>)</span><span class='hs-layout'>)</span> <span class='hs-varid'>s</span>-</pre></div><div id="vector-module"><h1>Vector module</h1><p>This module contains a class for two-dimensional vectors, a strict datatype to instantiate it, and another instance for signals of the same type.</p><pre><span class='hs-varop'>&gt;</span> <span class='hs-comment'>{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances, TypeSynonymInstances #-}</span>+</pre><h1 id="vector-module">Vector module</h1><p>This module contains a class for two-dimensional vectors, a strict datatype to instantiate it, and another instance for signals of the same type.</p><pre><span class='hs-varop'>&gt;</span> <span class='hs-comment'>{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances #-}</span> <span class='hs-varop'>&gt;</span> <span class='hs-varop'>&gt;</span> <span class='hs-keyword'>module</span> <span class='hs-conid'>Common</span><span class='hs-varop'>.</span><span class='hs-conid'>Vector</span> <span class='hs-keyword'>where</span> <span class='hs-varop'>&gt;</span> <span class='hs-varop'>&gt;</span> <span class='hs-keyword'>import</span> <span class='hs-conid'>Control</span><span class='hs-varop'>.</span><span class='hs-conid'>Applicative</span> <span class='hs-varop'>&gt;</span> <span class='hs-keyword'>import</span> <span class='hs-conid'>FRP</span><span class='hs-varop'>.</span><span class='hs-conid'>Elerea</span>-<span class='hs-varop'>&gt;</span> <span class='hs-keyword'>import</span> <span class='hs-conid'>Graphics</span><span class='hs-varop'>.</span><span class='hs-conid'>Rendering</span><span class='hs-varop'>.</span><span class='hs-conid'>OpenGL</span> <span class='hs-varop'>&gt;</span>-<span class='hs-varop'>&gt;</span> <span class='hs-keyword'>data</span> <span class='hs-conid'>Vec</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>V</span> <span class='hs-layout'>{</span> <span class='hs-varid'>getX</span> <span class='hs-keyglyph'>::</span> <span class='hs-varop'>!</span><span class='hs-conid'>GLfloat</span><span class='hs-layout'>,</span> <span class='hs-varid'>getY</span> <span class='hs-keyglyph'>::</span> <span class='hs-varop'>!</span><span class='hs-conid'>GLfloat</span> <span class='hs-layout'>}</span>+<span class='hs-varop'>&gt;</span> <span class='hs-keyword'>data</span> <span class='hs-conid'>Vec</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>V</span> <span class='hs-layout'>{</span> <span class='hs-varid'>getX</span> <span class='hs-keyglyph'>::</span> <span class='hs-varop'>!</span><span class='hs-conid'>Float</span><span class='hs-layout'>,</span> <span class='hs-varid'>getY</span> <span class='hs-keyglyph'>::</span> <span class='hs-varop'>!</span><span class='hs-conid'>Float</span> <span class='hs-layout'>}</span> <span class='hs-varop'>&gt;</span> <span class='hs-varop'>&gt;</span> <span class='hs-keyword'>infixl</span> <span class='hs-num'>7</span> <span class='hs-varop'>^*.</span> <span class='hs-varop'>&gt;</span> <span class='hs-keyword'>infixl</span> <span class='hs-num'>7</span> <span class='hs-varop'>.*^</span>@@ -214,7 +212,7 @@ <span class='hs-varop'>&gt;</span>     <span class='hs-varid'>dot</span> <span class='hs-keyglyph'>::</span> <span class='hs-varid'>v</span> <span class='hs-keyglyph'>&rarr;</span> <span class='hs-varid'>v</span> <span class='hs-keyglyph'>&rarr;</span> <span class='hs-varid'>c</span> <span class='hs-varop'>&gt;</span>     <span class='hs-varid'>cross</span> <span class='hs-keyglyph'>::</span> <span class='hs-varid'>v</span> <span class='hs-keyglyph'>&rarr;</span> <span class='hs-varid'>v</span> <span class='hs-keyglyph'>&rarr;</span> <span class='hs-varid'>c</span> <span class='hs-varop'>&gt;</span>-<span class='hs-varop'>&gt;</span> <span class='hs-keyword'>instance</span> <span class='hs-conid'>Vector2D</span> <span class='hs-conid'>Vec</span> <span class='hs-conid'>GLfloat</span> <span class='hs-keyword'>where</span>+<span class='hs-varop'>&gt;</span> <span class='hs-keyword'>instance</span> <span class='hs-conid'>Vector2D</span> <span class='hs-conid'>Vec</span> <span class='hs-conid'>Float</span> <span class='hs-keyword'>where</span> <span class='hs-varop'>&gt;</span>     <span class='hs-conid'>V</span> <span class='hs-varid'>x1</span> <span class='hs-varid'>y1</span> <span class='hs-varop'>^+^</span> <span class='hs-conid'>V</span> <span class='hs-varid'>x2</span> <span class='hs-varid'>y2</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>V</span> <span class='hs-layout'>(</span><span class='hs-varid'>x1</span><span class='hs-varop'>+</span><span class='hs-varid'>x2</span><span class='hs-layout'>)</span> <span class='hs-layout'>(</span><span class='hs-varid'>y1</span><span class='hs-varop'>+</span><span class='hs-varid'>y2</span><span class='hs-layout'>)</span> <span class='hs-varop'>&gt;</span>     <span class='hs-conid'>V</span> <span class='hs-varid'>x1</span> <span class='hs-varid'>y1</span> <span class='hs-varop'>^-^</span> <span class='hs-conid'>V</span> <span class='hs-varid'>x2</span> <span class='hs-varid'>y2</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>V</span> <span class='hs-layout'>(</span><span class='hs-varid'>x1</span><span class='hs-comment'>-</span><span class='hs-varid'>x2</span><span class='hs-layout'>)</span> <span class='hs-layout'>(</span><span class='hs-varid'>y1</span><span class='hs-comment'>-</span><span class='hs-varid'>y2</span><span class='hs-layout'>)</span> <span class='hs-varop'>&gt;</span>     <span class='hs-conid'>V</span> <span class='hs-varid'>x</span> <span class='hs-varid'>y</span> <span class='hs-varop'>^*.</span> <span class='hs-varid'>t</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>V</span> <span class='hs-layout'>(</span><span class='hs-varid'>x</span><span class='hs-varop'>*</span><span class='hs-varid'>t</span><span class='hs-layout'>)</span> <span class='hs-layout'>(</span><span class='hs-varid'>y</span><span class='hs-varop'>*</span><span class='hs-varid'>t</span><span class='hs-layout'>)</span>@@ -223,7 +221,7 @@ <span class='hs-varop'>&gt;</span>     <span class='hs-conid'>V</span> <span class='hs-varid'>x1</span> <span class='hs-varid'>y1</span> <span class='hs-varop'>`dot`</span> <span class='hs-conid'>V</span> <span class='hs-varid'>x2</span> <span class='hs-varid'>y2</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>x1</span><span class='hs-varop'>*</span><span class='hs-varid'>y1</span><span class='hs-varop'>+</span><span class='hs-varid'>x2</span><span class='hs-varop'>*</span><span class='hs-varid'>y2</span> <span class='hs-varop'>&gt;</span>     <span class='hs-conid'>V</span> <span class='hs-varid'>x1</span> <span class='hs-varid'>y1</span> <span class='hs-varop'>`cross`</span> <span class='hs-conid'>V</span> <span class='hs-varid'>x2</span> <span class='hs-varid'>y2</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>x1</span><span class='hs-varop'>*</span><span class='hs-varid'>y2</span><span class='hs-comment'>-</span><span class='hs-varid'>x2</span><span class='hs-varop'>*</span><span class='hs-varid'>y1</span> <span class='hs-varop'>&gt;</span>-<span class='hs-varop'>&gt;</span> <span class='hs-keyword'>instance</span> <span class='hs-conid'>Vector2D</span> <span class='hs-layout'>(</span><span class='hs-conid'>Signal</span> <span class='hs-conid'>Vec</span><span class='hs-layout'>)</span> <span class='hs-layout'>(</span><span class='hs-conid'>Signal</span> <span class='hs-conid'>GLfloat</span><span class='hs-layout'>)</span> <span class='hs-keyword'>where</span>+<span class='hs-varop'>&gt;</span> <span class='hs-keyword'>instance</span> <span class='hs-conid'>Vector2D</span> <span class='hs-layout'>(</span><span class='hs-conid'>Signal</span> <span class='hs-conid'>Vec</span><span class='hs-layout'>)</span> <span class='hs-layout'>(</span><span class='hs-conid'>Signal</span> <span class='hs-conid'>Float</span><span class='hs-layout'>)</span> <span class='hs-keyword'>where</span> <span class='hs-varop'>&gt;</span>     <span class='hs-layout'>(</span><span class='hs-varop'>^+^</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>liftA2</span> <span class='hs-layout'>(</span><span class='hs-varop'>^+^</span><span class='hs-layout'>)</span> <span class='hs-varop'>&gt;</span>     <span class='hs-layout'>(</span><span class='hs-varop'>^-^</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>liftA2</span> <span class='hs-layout'>(</span><span class='hs-varop'>^-^</span><span class='hs-layout'>)</span> <span class='hs-varop'>&gt;</span>     <span class='hs-layout'>(</span><span class='hs-varop'>^*.</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>liftA2</span> <span class='hs-layout'>(</span><span class='hs-varop'>^*.</span><span class='hs-layout'>)</span>@@ -231,7 +229,5 @@ <span class='hs-varop'>&gt;</span>     <span class='hs-varid'>vnull</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>pure</span> <span class='hs-varid'>vnull</span> <span class='hs-varop'>&gt;</span>     <span class='hs-varid'>dot</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>liftA2</span> <span class='hs-varid'>dot</span> <span class='hs-varop'>&gt;</span>     <span class='hs-varid'>cross</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>liftA2</span> <span class='hs-varid'>cross</span>-</pre></body>-</html>--</div></body></html>+</pre>+</body></html>
doc/Chase.html view
@@ -1,6 +1,5 @@ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><title></title><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><meta name="generator" content="pandoc" /><link rel="stylesheet" href="hscolour.css" type="text/css" media="all" />-</head><body><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">-<html><head><!-- Generated by HsColour, http://www.cs.york.ac.uk/fp/darcs/hscolour/ --><title>Haskell code</title> <link type='text/css' rel='stylesheet' href='hscolour.css' /> </head><body><div id="elerea-chase-example"><h1>Elerea Chase example</h1><p>This is a minimal example to show how to define signals that can be mutually recursive and can optionally depend on user input too. The grey square accelerates towards the red square at a rate proportional to their relative position, and it can be given a momentary impulse with the left mouse button.</p><p>For a slightly more complex example check out <code>Breakout.lhs</code>.</p><pre><span class='hs-varop'>&gt;</span> <span class='hs-comment'>{-# LANGUAGE RecursiveDo #-}</span>+</head><body><h1 id="elerea-chase-example">Elerea Chase example</h1><p>This is a minimal example to show how to define signals that can be mutually recursive and can optionally depend on user input too. The grey square accelerates towards the red square at a rate proportional to their relative position, and it can be given a momentary impulse with the left mouse button.</p><p>For a slightly more complex example check out <code>Breakout.lhs</code>.</p><pre><span class='hs-varop'>&gt;</span> <span class='hs-comment'>{-# LANGUAGE RecursiveDo #-}</span> <span class='hs-varop'>&gt;</span> <span class='hs-varop'>&gt;</span> <span class='hs-keyword'>module</span> <span class='hs-conid'>Main</span> <span class='hs-keyword'>where</span> <span class='hs-varop'>&gt;</span> @@ -84,7 +83,7 @@ <span class='hs-varop'>&gt;</span>   <span class='hs-varid'>scale</span> <span class='hs-num'>1</span> <span class='hs-layout'>(</span><span class='hs-varid'>fromIntegral</span> <span class='hs-varid'>w</span><span class='hs-varop'>/</span><span class='hs-varid'>fromIntegral</span> <span class='hs-varid'>h</span><span class='hs-layout'>)</span> <span class='hs-layout'>(</span><span class='hs-num'>1</span> <span class='hs-keyglyph'>::</span> <span class='hs-conid'>GLfloat</span><span class='hs-layout'>)</span> <span class='hs-varop'>&gt;</span>   <span class='hs-varop'>&gt;</span>   <span class='hs-varid'>matrixMode</span> <span class='hs-varop'>$=</span> <span class='hs-conid'>Modelview</span> <span class='hs-num'>0</span>-</pre></div><div id="utils-module"><h1>Utils module</h1><p>This module contains some functions that might make it into the core library eventually.</p><pre><span class='hs-varop'>&gt;</span> <span class='hs-keyword'>module</span> <span class='hs-conid'>Common</span><span class='hs-varop'>.</span><span class='hs-conid'>Utils</span> <span class='hs-keyword'>where</span>+</pre><h1 id="utils-module">Utils module</h1><p>This module contains some functions that might make it into the core library eventually.</p><pre><span class='hs-varop'>&gt;</span> <span class='hs-keyword'>module</span> <span class='hs-conid'>Common</span><span class='hs-varop'>.</span><span class='hs-conid'>Utils</span> <span class='hs-keyword'>where</span> <span class='hs-varop'>&gt;</span> <span class='hs-varop'>&gt;</span> <span class='hs-keyword'>import</span> <span class='hs-conid'>Control</span><span class='hs-varop'>.</span><span class='hs-conid'>Applicative</span> <span class='hs-varop'>&gt;</span> <span class='hs-keyword'>import</span> <span class='hs-conid'>Control</span><span class='hs-varop'>.</span><span class='hs-conid'>Monad</span>@@ -99,15 +98,14 @@ <span class='hs-varop'>&gt;</span>     <span class='hs-conid'>Nothing</span> <span class='hs-keyglyph'>&rarr;</span> <span class='hs-varid'>return</span> <span class='hs-conid'>()</span> </pre><p>A scalar integral function for <code>Fractional</code> instances.</p><pre><span class='hs-varop'>&gt;</span> <span class='hs-varid'>integral</span> <span class='hs-varid'>v0</span> <span class='hs-varid'>s</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>transfer</span> <span class='hs-varid'>v0</span> <span class='hs-layout'>(</span><span class='hs-keyglyph'>\</span><span class='hs-varid'>dt</span> <span class='hs-varid'>v</span> <span class='hs-varid'>v0</span> <span class='hs-keyglyph'>&rarr;</span> <span class='hs-varid'>v0</span><span class='hs-varop'>+</span><span class='hs-varid'>v</span><span class='hs-varop'>*</span><span class='hs-varid'>realToFrac</span> <span class='hs-varid'>dt</span><span class='hs-layout'>)</span> <span class='hs-varid'>s</span> </pre><p>An integral function for two-dimensional vectors defined in the <code>Vector</code> module.</p><pre><span class='hs-varop'>&gt;</span> <span class='hs-varid'>integralVec</span> <span class='hs-varid'>v0</span> <span class='hs-varid'>s</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>transfer</span> <span class='hs-varid'>v0</span> <span class='hs-layout'>(</span><span class='hs-keyglyph'>\</span><span class='hs-varid'>dt</span> <span class='hs-varid'>v</span> <span class='hs-varid'>v0</span> <span class='hs-keyglyph'>&rarr;</span> <span class='hs-varid'>v0</span><span class='hs-varop'>^+^</span><span class='hs-layout'>(</span><span class='hs-varid'>v</span><span class='hs-varop'>^*.</span><span class='hs-varid'>realToFrac</span> <span class='hs-varid'>dt</span><span class='hs-layout'>)</span><span class='hs-layout'>)</span> <span class='hs-varid'>s</span>-</pre></div><div id="vector-module"><h1>Vector module</h1><p>This module contains a class for two-dimensional vectors, a strict datatype to instantiate it, and another instance for signals of the same type.</p><pre><span class='hs-varop'>&gt;</span> <span class='hs-comment'>{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances, TypeSynonymInstances #-}</span>+</pre><h1 id="vector-module">Vector module</h1><p>This module contains a class for two-dimensional vectors, a strict datatype to instantiate it, and another instance for signals of the same type.</p><pre><span class='hs-varop'>&gt;</span> <span class='hs-comment'>{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances #-}</span> <span class='hs-varop'>&gt;</span> <span class='hs-varop'>&gt;</span> <span class='hs-keyword'>module</span> <span class='hs-conid'>Common</span><span class='hs-varop'>.</span><span class='hs-conid'>Vector</span> <span class='hs-keyword'>where</span> <span class='hs-varop'>&gt;</span> <span class='hs-varop'>&gt;</span> <span class='hs-keyword'>import</span> <span class='hs-conid'>Control</span><span class='hs-varop'>.</span><span class='hs-conid'>Applicative</span> <span class='hs-varop'>&gt;</span> <span class='hs-keyword'>import</span> <span class='hs-conid'>FRP</span><span class='hs-varop'>.</span><span class='hs-conid'>Elerea</span>-<span class='hs-varop'>&gt;</span> <span class='hs-keyword'>import</span> <span class='hs-conid'>Graphics</span><span class='hs-varop'>.</span><span class='hs-conid'>Rendering</span><span class='hs-varop'>.</span><span class='hs-conid'>OpenGL</span> <span class='hs-varop'>&gt;</span>-<span class='hs-varop'>&gt;</span> <span class='hs-keyword'>data</span> <span class='hs-conid'>Vec</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>V</span> <span class='hs-layout'>{</span> <span class='hs-varid'>getX</span> <span class='hs-keyglyph'>::</span> <span class='hs-varop'>!</span><span class='hs-conid'>GLfloat</span><span class='hs-layout'>,</span> <span class='hs-varid'>getY</span> <span class='hs-keyglyph'>::</span> <span class='hs-varop'>!</span><span class='hs-conid'>GLfloat</span> <span class='hs-layout'>}</span>+<span class='hs-varop'>&gt;</span> <span class='hs-keyword'>data</span> <span class='hs-conid'>Vec</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>V</span> <span class='hs-layout'>{</span> <span class='hs-varid'>getX</span> <span class='hs-keyglyph'>::</span> <span class='hs-varop'>!</span><span class='hs-conid'>Float</span><span class='hs-layout'>,</span> <span class='hs-varid'>getY</span> <span class='hs-keyglyph'>::</span> <span class='hs-varop'>!</span><span class='hs-conid'>Float</span> <span class='hs-layout'>}</span> <span class='hs-varop'>&gt;</span> <span class='hs-varop'>&gt;</span> <span class='hs-keyword'>infixl</span> <span class='hs-num'>7</span> <span class='hs-varop'>^*.</span> <span class='hs-varop'>&gt;</span> <span class='hs-keyword'>infixl</span> <span class='hs-num'>7</span> <span class='hs-varop'>.*^</span>@@ -125,7 +123,7 @@ <span class='hs-varop'>&gt;</span>     <span class='hs-varid'>dot</span> <span class='hs-keyglyph'>::</span> <span class='hs-varid'>v</span> <span class='hs-keyglyph'>&rarr;</span> <span class='hs-varid'>v</span> <span class='hs-keyglyph'>&rarr;</span> <span class='hs-varid'>c</span> <span class='hs-varop'>&gt;</span>     <span class='hs-varid'>cross</span> <span class='hs-keyglyph'>::</span> <span class='hs-varid'>v</span> <span class='hs-keyglyph'>&rarr;</span> <span class='hs-varid'>v</span> <span class='hs-keyglyph'>&rarr;</span> <span class='hs-varid'>c</span> <span class='hs-varop'>&gt;</span>-<span class='hs-varop'>&gt;</span> <span class='hs-keyword'>instance</span> <span class='hs-conid'>Vector2D</span> <span class='hs-conid'>Vec</span> <span class='hs-conid'>GLfloat</span> <span class='hs-keyword'>where</span>+<span class='hs-varop'>&gt;</span> <span class='hs-keyword'>instance</span> <span class='hs-conid'>Vector2D</span> <span class='hs-conid'>Vec</span> <span class='hs-conid'>Float</span> <span class='hs-keyword'>where</span> <span class='hs-varop'>&gt;</span>     <span class='hs-conid'>V</span> <span class='hs-varid'>x1</span> <span class='hs-varid'>y1</span> <span class='hs-varop'>^+^</span> <span class='hs-conid'>V</span> <span class='hs-varid'>x2</span> <span class='hs-varid'>y2</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>V</span> <span class='hs-layout'>(</span><span class='hs-varid'>x1</span><span class='hs-varop'>+</span><span class='hs-varid'>x2</span><span class='hs-layout'>)</span> <span class='hs-layout'>(</span><span class='hs-varid'>y1</span><span class='hs-varop'>+</span><span class='hs-varid'>y2</span><span class='hs-layout'>)</span> <span class='hs-varop'>&gt;</span>     <span class='hs-conid'>V</span> <span class='hs-varid'>x1</span> <span class='hs-varid'>y1</span> <span class='hs-varop'>^-^</span> <span class='hs-conid'>V</span> <span class='hs-varid'>x2</span> <span class='hs-varid'>y2</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>V</span> <span class='hs-layout'>(</span><span class='hs-varid'>x1</span><span class='hs-comment'>-</span><span class='hs-varid'>x2</span><span class='hs-layout'>)</span> <span class='hs-layout'>(</span><span class='hs-varid'>y1</span><span class='hs-comment'>-</span><span class='hs-varid'>y2</span><span class='hs-layout'>)</span> <span class='hs-varop'>&gt;</span>     <span class='hs-conid'>V</span> <span class='hs-varid'>x</span> <span class='hs-varid'>y</span> <span class='hs-varop'>^*.</span> <span class='hs-varid'>t</span> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>V</span> <span class='hs-layout'>(</span><span class='hs-varid'>x</span><span class='hs-varop'>*</span><span class='hs-varid'>t</span><span class='hs-layout'>)</span> <span class='hs-layout'>(</span><span class='hs-varid'>y</span><span class='hs-varop'>*</span><span class='hs-varid'>t</span><span class='hs-layout'>)</span>@@ -134,7 +132,7 @@ <span class='hs-varop'>&gt;</span>     <span class='hs-conid'>V</span> <span class='hs-varid'>x1</span> <span class='hs-varid'>y1</span> <span class='hs-varop'>`dot`</span> <span class='hs-conid'>V</span> <span class='hs-varid'>x2</span> <span class='hs-varid'>y2</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>x1</span><span class='hs-varop'>*</span><span class='hs-varid'>y1</span><span class='hs-varop'>+</span><span class='hs-varid'>x2</span><span class='hs-varop'>*</span><span class='hs-varid'>y2</span> <span class='hs-varop'>&gt;</span>     <span class='hs-conid'>V</span> <span class='hs-varid'>x1</span> <span class='hs-varid'>y1</span> <span class='hs-varop'>`cross`</span> <span class='hs-conid'>V</span> <span class='hs-varid'>x2</span> <span class='hs-varid'>y2</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>x1</span><span class='hs-varop'>*</span><span class='hs-varid'>y2</span><span class='hs-comment'>-</span><span class='hs-varid'>x2</span><span class='hs-varop'>*</span><span class='hs-varid'>y1</span> <span class='hs-varop'>&gt;</span>-<span class='hs-varop'>&gt;</span> <span class='hs-keyword'>instance</span> <span class='hs-conid'>Vector2D</span> <span class='hs-layout'>(</span><span class='hs-conid'>Signal</span> <span class='hs-conid'>Vec</span><span class='hs-layout'>)</span> <span class='hs-layout'>(</span><span class='hs-conid'>Signal</span> <span class='hs-conid'>GLfloat</span><span class='hs-layout'>)</span> <span class='hs-keyword'>where</span>+<span class='hs-varop'>&gt;</span> <span class='hs-keyword'>instance</span> <span class='hs-conid'>Vector2D</span> <span class='hs-layout'>(</span><span class='hs-conid'>Signal</span> <span class='hs-conid'>Vec</span><span class='hs-layout'>)</span> <span class='hs-layout'>(</span><span class='hs-conid'>Signal</span> <span class='hs-conid'>Float</span><span class='hs-layout'>)</span> <span class='hs-keyword'>where</span> <span class='hs-varop'>&gt;</span>     <span class='hs-layout'>(</span><span class='hs-varop'>^+^</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>liftA2</span> <span class='hs-layout'>(</span><span class='hs-varop'>^+^</span><span class='hs-layout'>)</span> <span class='hs-varop'>&gt;</span>     <span class='hs-layout'>(</span><span class='hs-varop'>^-^</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>liftA2</span> <span class='hs-layout'>(</span><span class='hs-varop'>^-^</span><span class='hs-layout'>)</span> <span class='hs-varop'>&gt;</span>     <span class='hs-layout'>(</span><span class='hs-varop'>^*.</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>liftA2</span> <span class='hs-layout'>(</span><span class='hs-varop'>^*.</span><span class='hs-layout'>)</span>@@ -142,7 +140,5 @@ <span class='hs-varop'>&gt;</span>     <span class='hs-varid'>vnull</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>pure</span> <span class='hs-varid'>vnull</span> <span class='hs-varop'>&gt;</span>     <span class='hs-varid'>dot</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>liftA2</span> <span class='hs-varid'>dot</span> <span class='hs-varop'>&gt;</span>     <span class='hs-varid'>cross</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>liftA2</span> <span class='hs-varid'>cross</span>-</pre></body>-</html>--</div></body></html>+</pre>+</body></html>
elerea-examples.cabal view
@@ -1,5 +1,5 @@ Name:                elerea-examples-Version:             1.2.0+Version:             2.0.0 Cabal-Version:       >= 1.2 Synopsis:            Example applications for Elerea Category:            reactivity, FRP@@ -12,18 +12,19 @@   .   The programs included are the following:   .-  * chase: a minimal example that demonstrates reactivity and mutually-    recursive signals+  * bounce (current): an example for creating dynamic collections of+    signals with the experimental interface; left click to create+    balls, drag existing balls with left button to propel them and+    drag with right to select balls for deletion (upon release)   .-  * breakout: a not too fancy breakout clone that also demonstrates-    Graphviz output; you can get an SVG rendition of the signal-    structure with the following command if Graphviz is installed:-    @elerea-breakout --dump-dot | dot -Tsvg -o breakout.svg@+  * chase (legacy): a minimal example that demonstrates reactivity and+    mutually recursive signals   .-  * bounce: an example for creating dynamic collections of signals-    with the experimental interface; left click to create balls, drag-    existing balls with left button to propel them and drag with right-    to select balls for deletion (upon release)+  * breakout (legacy): a not too fancy breakout clone that also+    demonstrates Graphviz output; you can get an SVG rendition of the+    signal structure with the following command if Graphviz is+    installed: @elerea-breakout --dump-dot | dot -Tsvg -o+    breakout.svg@  Author:              Patai Gergely Maintainer:          Patai Gergely (patai@iit.bme.hu)@@ -53,19 +54,19 @@   Executable:        elerea-bounce   HS-Source-Dirs:    src/Bounce   Main-IS:           Main.hs-  Build-Depends:     base >= 3 && < 5, elerea >= 1.2, OpenGL, GLFW >= 0.4-  GHC-Options:       -O2+  Build-Depends:     base >= 3 && < 5, elerea >= 2.0.0, OpenGL, GLFW >= 0.4+  GHC-Options:       -O2 -fno-warn-deprecated-flags  Executable elerea-breakout   Executable:        elerea-breakout   HS-Source-Dirs:    src   Main-IS:           Breakout.lhs-  Build-Depends:     base >= 3 && < 5, elerea >= 1.0, OpenGL, GLFW >= 0.4-  GHC-Options:       -O2+  Build-Depends:     base >= 3 && < 5, elerea >= 2.0.0, OpenGL, GLFW >= 0.4+  GHC-Options:       -O2 -fno-warn-deprecated-flags  Executable elerea-chase   Executable:        elerea-chase   HS-Source-Dirs:    src   Main-IS:           Chase.lhs-  Build-Depends:     base >= 3 && < 5, elerea >= 1.0, OpenGL, GLFW >= 0.4-  GHC-Options:       -O2+  Build-Depends:     base >= 3 && < 5, elerea >= 2.0.0, OpenGL, GLFW >= 0.4+  GHC-Options:       -O2 -fno-warn-deprecated-flags
src/Bounce/Event.hs view
@@ -6,41 +6,41 @@ import Control.Monad import Control.Monad.Fix import Data.Maybe-import FRP.Elerea.Experimental+import FRP.Elerea.Delayed  import Util -{-| Events are signals with an option type. -}+-- | Events are signals with an option type. type Event p a = Signal p (Maybe a) -{-| Sample a signal whenever a changing condition is true. -}+-- | Sample a signal whenever a changing condition is true. ifE :: Signal p Bool -> Signal p a -> Event p a ifE c s = c >>= \b -> if b then Just <$> s else return Nothing -{-| Left-biased merge. -}+-- | Left-biased merge. leftE :: Event p a -> Event p a -> Event p a leftE e1 e2 = e1 >>= maybeE e2 -{-| Right-biased merge. -}+-- | Right-biased merge. rightE :: Event p a -> Event p a -> Event p a rightE e1 e2 = e2 >>= maybeE e1 -{-| Left-biased merge of several events. -}+-- | Left-biased merge of several events. mergeE :: [Event p a] -> Event p a mergeE []     = return Nothing mergeE (e:es) = e >>= maybeE (mergeE es) -{-| Maintain a changing list of entities fed in as events along with a-function to derive the corresponding signal of the removal condition-(the signal is removed when the associated removal signal is 'True' for-the first time). -}+-- | Maintain a changing list of entities fed in as events along with+-- a function to derive the corresponding signal of the removal+-- condition (the signal is removed when the associated removal signal+-- is 'True' for the first time). collectE :: Event p a -> (a -> Signal p Bool) -> SignalGen p (Signal p [a]) collectE e f = mdo   col <- delay [] col'   col' <- dmemo [] $ filterM (fmap not . f) =<< liftM2 ((++).maybeToList) e col   return col' -{-| A helper function equivalent to @flip maybe (return.Just)@. -}+-- | A helper function equivalent to @flip maybe (return.Just)@. maybeE :: Event p a -> Maybe a -> Event p a maybeE e Nothing = e maybeE _ jx      = return jx
src/Bounce/Main.hs view
@@ -7,7 +7,7 @@ import Data.IORef import Data.List import Data.Maybe-import FRP.Elerea.Experimental+import FRP.Elerea.Delayed import Graphics.UI.GLFW as GLFW import Graphics.Rendering.OpenGL @@ -27,7 +27,7 @@                  , ballDrag :: Bool                  } --- A box with bouncing balls inside:  +-- A box with bouncing balls inside: -- * left click creates a new ball, -- * existing balls can be dragged and propelled with the left button, -- * dragging with the right button creates a rectangle; every ball@@ -52,7 +52,7 @@    frameCount <- stateful 0 (const (+1))   fps <- derivT 2 frameCount-  +   return $ renderFun <$> ballData <*> killDrag <*> fps  -- Flipflop signal: turns true when the first event fires, turns false@@ -77,7 +77,7 @@   dragEnd <- edge (not <$> mousePress)   drag <- flipflop dragBegin dragEnd   dragVel <- derivTV 0.05 mousePos-  +   let collHorz (V vx _) (V px _) = collFrame vx px       collVert (V _ vy) (V _ py) = collFrame vy py       collFrame v p = abs (p-0.5) > 0.5-(frameThickness+ballSize/2) && (p-0.5)*v > 0@@ -145,7 +145,7 @@   loadIdentity   scale (min 2 r') (min 2 r) (1 :: GLfloat)   translate $ Vector3 (-0.5) (-0.5) (0 :: GLfloat)-	+   matrixMode $= Modelview 0  render unitCircle bs rect fps = do@@ -162,13 +162,13 @@    clear [ColorBuffer]   loadIdentity-  +   color $ Color4 0.6 0.6 0.6 (1 :: GLfloat)   drawRectangle 0 0 1 frameThickness   drawRectangle 0 (1-frameThickness) 1 frameThickness   drawRectangle 0 0 frameThickness 1   drawRectangle (1-frameThickness) 0 frameThickness 1-  +   forM_ bs $ \b -> do     case ballCol b of       Nothing -> color $ Color4 0 0 0.7 (1 :: GLfloat)@@ -193,7 +193,7 @@ readInput mousePos mouseBut closed = do   t <- get time   time $= 0-  +   Position x y <- get GLFW.mousePos   Size w h <- get windowSize   let x' = fromIntegral x@@ -203,7 +203,7 @@       mx = (x'-max 0 (w'-h')/2)/min w' h'       my = (y'-max 0 (h'-w')/2)/min w' h'   mousePos (V mx (1-my))-  +   bl <- getMouseButton ButtonLeft   br <- getMouseButton ButtonRight   mouseBut (bl == Press, br == Press)
src/Bounce/Math.hs view
@@ -4,7 +4,7 @@  import Control.Applicative import Data.List-import FRP.Elerea.Experimental+import FRP.Elerea.Delayed  import Vector import Util
src/Bounce/Util.hs view
@@ -1,7 +1,7 @@ module Util where  import Control.Applicative-import FRP.Elerea.Experimental+import FRP.Elerea.Delayed  -- Lifted conditional. ifS c s1 s2 = c >>= \b -> if b then s1 else s2@@ -19,3 +19,58 @@  -- Optional delay. Should memo behave like this? dmemo = flip transfer (const const)++-- Functions moved over from the old Experimental top module++infix  4 ==@, /=@, <@, <=@, >=@, >@+infixr 3 &&@+infixr 2 ||@+infix  2 -->++-- | The 'edge' transfer function takes a bool signal and emits+-- another bool signal that turns true only at the moment when there+-- is a rising edge on the input.+edge :: Signal p Bool -> SignalGen p (Signal p Bool)+edge b = delay True b >>= \db -> return $ (not <$> db) &&@ b++-- | The '-->' transfer function behaves as a latch on a 'Maybe'+-- input: it keeps its state when the input is 'Nothing', and replaces+-- it with the input otherwise.+(-->) :: a                        -- ^ Initial output+      -> Signal p (Maybe a)       -- ^ Maybe signal to latch on+      -> SignalGen p (Signal p a)+x0 --> s = transfer x0 store s+    where store _ Nothing  x = x+          store _ (Just x) _ = x++-- | Point-wise equality of two signals.+(==@) :: Eq a => Signal p a -> Signal p a -> Signal p Bool+(==@) = liftA2 (==)++-- | Point-wise inequality of two signals.+(/=@) :: Eq a => Signal p a -> Signal p a -> Signal p Bool+(/=@) = liftA2 (/=)++-- | Point-wise comparison of two signals.+(<@) :: Ord a => Signal p a -> Signal p a -> Signal p Bool+(<@) = liftA2 (<)++-- | Point-wise comparison of two signals.+(<=@) :: Ord a => Signal p a -> Signal p a -> Signal p Bool+(<=@) = liftA2 (<=)++-- | Point-wise comparison of two signals.+(>=@) :: Ord a => Signal p a -> Signal p a -> Signal p Bool+(>=@) = liftA2 (>=)++-- | Point-wise comparison of two signals.+(>@) :: Ord a => Signal p a -> Signal p a -> Signal p Bool+(>@) = liftA2 (>)++-- | Point-wise OR of two boolean signals.+(||@) :: Signal p Bool -> Signal p Bool -> Signal p Bool+s1 ||@ s2 = s1 >>= \b -> if b then return True else s2++-- | Point-wise AND of two boolean signals.+(&&@) :: Signal p Bool -> Signal p Bool -> Signal p Bool+s1 &&@ s2 = s1 >>= \b -> if b then s2 else return False
src/Bounce/Vector.hs view
@@ -3,7 +3,7 @@ module Vector where  import Control.Applicative-import FRP.Elerea.Experimental+import FRP.Elerea.Delayed import Graphics.Rendering.OpenGL  data Vec = V { getX :: {-# UNPACK #-} !GLfloat, getY :: {-# UNPACK #-} !GLfloat }
src/Breakout.lhs view
@@ -34,7 +34,7 @@ > {-# LANGUAGE RecursiveDo #-} > > module Main where-> +> > import Control.Applicative > import Control.Concurrent > import Control.Monad@@ -42,8 +42,8 @@ > import Data.List > import Data.Maybe > import Data.Traversable hiding (mapM)-> import FRP.Elerea-> import FRP.Elerea.Graph+> import FRP.Elerea.Legacy+> import FRP.Elerea.Legacy.Graph > import Graphics.UI.GLFW as GLFW > import Graphics.Rendering.OpenGL > import System.Environment@@ -117,22 +117,22 @@ >   initialize >   openWindow (Size 640 480) [DisplayRGBBits 8 8 8, DisplayAlphaBits 8] Window >   windowTitle $= "Elerea Breakout"-> +> >   -- External signals available for the game logic >   (windowSize,windowSizeSink) <- external vnull >   (mousePosition,mousePositionSink) <- external vnull-> +> >   -- Wrapping up the init phase >   closed <- newIORef False >   windowSizeCallback $= resizeGLScene windowSizeSink >   windowCloseCallback $= writeIORef closed True >   initGL 640 480-> +> >   -- All we need to get going is an IO-valued signal and an IO >   -- function to update the external signals >   game <- createSignal $ breakout mousePosition windowSize >   driveNetwork game (readInput mousePositionSink closed)-> +> >   -- The inevitable sad ending >   closeWindow >@@ -227,7 +227,7 @@ >       getBrickData (x,y,s,_,_) = (x,y,s) >       getBrickHColl (_,_,_,c,_) = c >       getBrickVColl (_,_,_,_,c) = c->       +> >       evolveBrick dt _   (x,y,Dying a,_,_) = (x,y,Dying (a-realToFrac dt*brickFade),False,False) >       evolveBrick dt (V bx by) (x,y,_,_,_) = (x,y,if isKilled then Dying 1 else Live,collHorz,collVert) >           where isKilled = isHit || by < -fieldH-ballH@@ -297,7 +297,7 @@ >           let a = 2*pi*fromIntegral i/fromIntegral n >           vertex $ Vertex3 (xc+xs/2*sin a) (yc+ys/2*cos a) (0 :: GLfloat) >           vertex $ Vertex3 xc yc (0 :: GLfloat)-> +> >   clear [ColorBuffer] > >   color $ Color4 0.2 0.2 0.2 (1 :: GLfloat)@@ -311,7 +311,7 @@ > >   color $ Color4 1 1 1 (0.6 :: GLfloat) >   drawEllipse ballX ballY ballW ballH 20-> +> >   color $ Color4 0.3 0.4 0.8 (0.5 :: GLfloat) >   drawRect playerX playerY playerW playerH >@@ -358,11 +358,11 @@  > resizeGLScene winSize size@(Size w h) = do >   winSize (V (fromIntegral w) (fromIntegral h))-> +> >   viewport $= (Position 0 0,size)-> +> >   matrixMode $= Projection >   loadIdentity >   scale 1 (fromIntegral w/fromIntegral h) (1 :: GLfloat)-> 	+> >   matrixMode $= Modelview 0
src/Chase.lhs view
@@ -12,13 +12,13 @@ > {-# LANGUAGE RecursiveDo #-} > > module Main where-> +> > import Control.Applicative > import Data.IORef-> import FRP.Elerea+> import FRP.Elerea.Legacy > import Graphics.UI.GLFW as GLFW > import Graphics.Rendering.OpenGL-> +> > import Common.Utils > import Common.Vector @@ -31,16 +31,16 @@ >   initialize >   openWindow (Size 640 480) [DisplayRGBBits 8 8 8, DisplayAlphaBits 8, DisplayDepthBits 24] Window >   windowTitle $= "Elerea Chase"-> +> >   (windowSize,windowSizeSink) <- external vnull >   (mousePosition,mousePositionSink) <- external vnull >   (mousePress,mousePressSink) <- external False-> +> >   closed <- newIORef False >   windowSizeCallback $= resizeGLScene windowSizeSink >   windowCloseCallback $= writeIORef closed True >   initGL 640 480-> +> >   greyPos <- createSignal $ mdo >         mouseClick <- edge mousePress >@@ -54,7 +54,7 @@ > >   driveNetwork (render <$> windowSize <*> mousePosition <*> greyPos) >                (readInput mousePositionSink mousePressSink closed)-> +> >   closeWindow  The `render` function takes a snapshot of the system (window size and@@ -71,14 +71,14 @@ >           vertex $ Vertex3 ( s) (-s) (0 :: GLfloat) >           vertex $ Vertex3 ( s) ( s) (0 :: GLfloat) >           vertex $ Vertex3 (-s) ( s) (0 :: GLfloat)-> +> >   clear [ColorBuffer]->  +> >   color $ Color4 1 0 0 (0.5 :: GLfloat) >   drawSquare cx cy 0.05 >   color $ Color4 1 1 1 (0.6 :: GLfloat) >   drawSquare ox oy 0.03-> +> >   flush >   swapBuffers @@ -110,11 +110,11 @@  > resizeGLScene winSize size@(Size w h) = do >   winSize (V (fromIntegral w) (fromIntegral h))-> +> >   viewport $= (Position 0 0,size)-> +> >   matrixMode $= Projection >   loadIdentity >   scale 1 (fromIntegral w/fromIntegral h) (1 :: GLfloat)-> 	+> >   matrixMode $= Modelview 0
src/Common/Utils.lhs view
@@ -7,7 +7,7 @@ > > import Control.Applicative > import Control.Monad-> import FRP.Elerea+> import FRP.Elerea.Legacy > > import Common.Vector 
src/Common/Vector.lhs view
@@ -10,7 +10,7 @@ > module Common.Vector where > > import Control.Applicative-> import FRP.Elerea+> import FRP.Elerea.Legacy > import Graphics.Rendering.OpenGL > > data Vec = V { getX :: !GLfloat, getY :: !GLfloat }