https://wiki.haskell.org/api.php?action=feedcontributions&user=Fa-ml&feedformat=atomHaskellWiki - User contributions [en]2022-08-14T12:17:58ZUser contributionsMediaWiki 1.31.7https://wiki.haskell.org/index.php?title=Applications_and_libraries/Games&diff=64754Applications and libraries/Games2021-09-25T15:50:16Z<p>Fa-ml: add venzone, swarm</p>
<hr />
<div>{{LibrariesPage}}<br />
<br />
See also: [[Game Development]]<br />
<br />
<br />
== Games ==<br />
<br />
See also the [http://hackage.haskell.org/packages/archive/pkg-list.html#cat:game Game] category on Hackage.<br />
<br />
; [http://allureofthestars.com Allure of the Stars]<br />
: A near-future Sci-Fi roguelike and tactical squad combat game. In brilliant 16-color ASCII, grid-based, turn-based, with a story, stealth, cool-down melee weapons, slow projectiles and fast explosions. Browser and native binaries. Free software using the {{HackagePackage|id=LambdaHack}} roguelike game engine. This incarnation complete, but in constant development and accepting contributions of all kinds.<br />
<br />
;{{HackagePackage|id=babylon}}<br />
: An implementation of a simple 2-player board game. Uses wxHaskell.<br />
<br />
;[https://www.haskell.org/communities/11-2015/html/report.html#sect7.13.5 Barbarossa]<br />
:A UCI chess engine written completely in Haskell<br />
<br />
;[https://github.com/plneappl/BeHaskelled BeHaskelled]<br />
: A Bejeweled clone written completely in Haskell with {{HackagePackage|id=gloss}}.<br />
<br />
;{{HackagePackage|id=board-games}}<br />
: Computer player algorithms for three games: Connect Four, Rows&Columns, Mastermind. Intended for running as a web server.<br />
<br />
;{{HackagePackage|id=boomslang}}<br />
: A clone of the popular Flash game Boomshine.<br />
<br />
;[https://github.com/yairchu/defend Defend The King from Forces of Different]<br />
: A simple multiplayer real time strategy game.<br />
<br />
; [http://www.increpare.com/2008/11/endless-cavern/ Endless Cavern]<br />
: A 2D procedurally-generated cave exploration game.<br />
<br />
;[http://sourceforge.net/projects/fooengine/?abmode=1 Foo]<br />
:Foo (abbreviation from football) is a playing machine of [http://en.wikipedia.org/wiki/Paper_Soccer Paper Soccer], a pencil and paper game for two players. It contains a simple interface using HOpenGL library and provides many playing algorithms.<br />
<br />
;[[Frag]]<br />
:Frag is a 3D first person shooting game written in Haskell, by Mun Hon Cheong. It uses Yampa, Quake 3 BSP level format and OpenGL. It is licensed under the GPL.<br />
<br />
;[http://mfuglos.github.io/jeopardy Fuglos Jeopardy]<br />
:Fuglos Jeopardy is a free implementation of a game resembling the popular quiz show 'Jeopardy'. It is written using Gtk2Hs as GUI toolkit. It is quite feature complete and easy to use. It contains support for LaTeX, so you can for example use LaTeX math syntax in your data sheets and thus organize a math jeopoardy event. Licensed under GPL3.<br />
<br />
;[[GeBoP]]<br />
:The General Boardgames Player, offers a set of board games: Ataxx, Bamp, Halma, Hex, Kram, Nim, Reversi, TicTacToe, and Zenix. It uses wxHaskell.<br />
<br />
; [http://folk.uio.no/carljsv/gorillabas/GorillaBAS-0.1.tar.gz GorillaBAS]<br />
: A concrete game from an attempt on defining computer games.<br />
<br />
; [https://github.com/ocharles/hadoom hadoom]<br />
:A clone of Doom, using reactive-banana, GTK, and the "diagrams" library.<br />
<br />
; [https://github.com/ivanperez-keera/haskanoid haskanoid]<br />
:A breakout game with SDL graphics and Kinect and Wiimote support. Written in FRP, there's a fork in Haskell for Android.<br />
<br />
;[http://www.informatik.uni-bremen.de/~cxl/lehre/pi3.ws01/asteroids/ Haskell in Space]<br />
:An asteroid like game<br />
<br />
;[http://www.hedgewars.org/ Hedgewars]<br />
:A turn-based artillery game. The game server is written in Haskell.<br />
<br />
;[http://www.cs.ox.ac.uk/people/ian.lynagh/Hetris/ Hetris]<br />
:ASCII Tetris in Haskell<br />
<br />
;{{HackagePackage|id=hfiar}}<br />
:Four in a Row in Haskell. Uses wxHaskell.<br />
<br />
;{{HackagePackage|id=hinvaders}}<br />
:A simple ANSI-graphics space invaders written entirely in Haskell 98.<br />
<br />
;[http://morgenthum.dev/static/lambda-heights Lambda-Heights]<br />
:A fast paced 2D arcade game written entirely in Haskell with the SDL2 binding.<br />
<br />
;[http://mu.org/~mux/LambdaChess/ LambdaChess]<br />
:GTK chess client<br />
<br />
;[https://github.com/mchakravarty/lazy-lambda Lazy Lambda]<br />
:Lazy Lambda is a simple Flappy Bird clone in Haskell, implemented with [https://github.com/mchakravarty/HaskellSpriteKit Haskell SpriteKit]. It was originally developed for the [https://speakerdeck.com/mchakravarty/playing-with-graphics-and-animations-in-haskell Compose :: Melbourne 2016 keynote], where it was live coded in the second half of the presentation.<br />
<br />
;[http://quasimal.com/projects/level_0.html Level 0]<br />
:A fun and featureful Snake II clone using SDL.<br />
<br />
;[http://www.ncc.up.pt/~pbv/stuff/lostcities/ Lost Cities]<br />
:A two-player card game where each player tries to mount profitable expeditions. It uses wxHaskell.<br />
<br />
;{{HackagePackage|id=mage}}<br />
:Nethack clone written in Haskell (The web site have [http://www.scannedinavian.com/~shae/mage-1.0pre35.tar.gz this mage-1.0.pre35.tar.gz file] containing an older version that was using Data.FiniteMap.) There seems to be a problem with newer curses library even with the more recent 1.1.0 version.<br />
<br />
;{{HackagePackage|id=MazesOfMonad}}<br />
:Role-Playing Game (influenced by Nethack), complete and fully playable. Console mode only. Modernized repository [https://github.com/bbarker/MazesOfMonad maintained on GitHub].<br />
<br />
;[http://www.geocities.jp/takascience/haskell/monadius_en.html Monadius]<br />
:Monadius is a shoot 'em up with the selection bar power-up system for Windows, written in Haskell (now on Hackage as {{HackagePackage|id=Monadius}}; see also the [http://www.youtube.com/watch?v=zqFgQiPKtOI video])<br />
<br />
;[http://mokehehe.blogspot.com/2009/04/super-nario-move-to-github.html Monao]<br />
:A Super Mario clone, using an SDL binding different from the one in Hackage: [https://github.com/mokehehe/monao Monao on github], [https://github.com/keera-studios/monao New maintained version on github]<br />
<br />
;[http://joyridelabs.de/game/ Nikki and the Robots]<br />
:A puzzle, platformer game.<br />
<br />
;[http://berlinbrowndev.blogspot.com/2007/09/octane-mech-opengl-haskell-based-mech.html Octane Mech]<br />
:Octane Mech, OpenGL Haskell based mech game<br />
<br />
;[http://sourceforge.net/projects/puzhs/ puzhs]<br />
:Haskell bindings to [https://code.google.com/p/puz/ libpuz]<br />
<br />
;[http://haskell-tetris.pbworks.com/w/page/16967421/Main OpenGL Tetris]<br />
:Tetris in Haskell with OpenGL<br />
<br />
;[http://srineet.brinkster.net/para/para.html Paratrooper]<br />
:Paratrooper is a simple action game that runs on Windows and is written in literate Haskell.<br />
<br />
;[http://raincat.bysusanlin.com/ Raincat]<br />
:2D puzzle game featuring a fuzzy little cat (uses GLUT)<br />
<br />
;[http://roguestar.downstairspeople.org Roguestar]<br />
:Roguestar is a science fiction adventure role playing game using Haskell and OpenGL.<br />
<br />
;{{HackagePackage|id=Shu-thing}}<br />
:A 2-D vector graphics upwards-scrolling keyboard-controlled shooter. You shoot the enemies while dodging their bullets until you reach and defeat the enemy.<br />
<br />
;{{HackagePackage|id=SpaceInvaders}}<br />
:A video game, based on [[Yampa]]<br />
<br />
;[https://github.com/byorgey/swarm/ swarm]<br />
:2D programming and resource gathering game.<br />
<br />
;{{HackagePackage|id=stunts}}<br />
:A revival of the classic racing game Stunts to serve as a non-toy-sized example for LambdaCube.<br />
<br />
;[https://github.com/nbartlomiej/tfoo Tfoo]<br />
:A simple Five in a Row game. Online, with server-sent events, deployed to [http://tfoo.herokuapp.com/ Heroku], open source.<br />
<br />
;[http://web.jfet.org/~kwantam/TriHs.tar.gz TriHs] (tar.gz)<br />
:A 1- or 2-player Tetris game using Gtk2Hs and Cairo.<br />
<br />
;[http://ariis.it/static/articles/venzone/page.html venzone]<br />
:ASCII platform/adventure.<br />
<br />
;[[wxAsteroids]]<br />
:Your space ship enters an asteroid belt, try to avoid collisions! wxAsteroids is based on wxHaskell.<br />
<br />
;[http://xiangqiboard.blogspot.com/2007/12/gnuxiangqi-angekndigt.html Xiangqiboard]<br />
:An implementation of xiangqi for Unix, using gtk2hs + cairo<br />
<br />
;{{HackagePackage | id =Yogurt}}<br />
:A functional MUD client featuring prioritized, regex-based hooks, variables, timers, logging, dynamic loading of Yogurt scripts and more. For example programs, please see [http://code.google.com/p/yogurt-mud/ Yogurt's home page]. <br />
<br />
=== Commercial games ===<br />
<br />
;[https://enpuzzled.haskell.games Enpuzzled]<br />
:2D puzzle game for iOS and Android written in Haskell using SDL2 graphics and the FRP implementation [https://github.com/ivanperez-keera/Yampa Yampa]. Created by [http://facebook.com/keerastudios Keera Studios], available on [https://apps.apple.com/us/app/enpuzzled/id1460083994 iTunes] and [https://play.google.com/store/apps/details?id=uk.co.keera.games.enpuzzled Google Play for Android].<br />
<br />
;[https://magiccookies.haskell.games Magic Cookies!]<br />
:A lights-out clone for iOS and Android written in Haskell using SDL2 graphics and the FRP implementation [https://github.com/ivanperez-keera/Yampa Yampa]. Created by [http://facebook.com/keerastudios Keera Studios], available on [https://itunes.apple.com/us/app/magic-cookies/id1244709871?mt=8 iTunes] and [https://play.google.com/store/apps/details?id=uk.co.keera.games.magiccookies Google Play for Android].<br />
<br />
=== Unfinished/in-progress games ===<br />
<br />
;[http://ipwnstudios.com/node/4 Bloodknight]<br />
:An action RPG for mobile devices<br />
<br />
; [https://github.com/ghulette/haskell-game-of-life haskell-game-of-life]<br />
: Conway's Game of Life<br />
<br />
; [https://github.com/EricThoma/hchess hchess]<br />
: Incomplete toy chess engine<br />
<br />
;[http://dotat.at/prog/life/hslife.hs HsLife]<br />
:A Haskell implementation of hashlife. It uses GLUT.<br />
<br />
== Game Engines and Libraries ==<br />
<br />
;[https://github.com/egonSchiele/actionkid actionkid]<br />
:A video game framework, with a [http://vimeo.com/109663514 video tutorial] and [https://github.com/egonSchiele/chips chips], a game based on it.<br />
<br />
;[[Bogre-Banana]]<br />
:A 3D game-engine for Haskell. It uses Haskell bindings to the OGRE 3D engine and OIS input system and a library called reactive-banana, to create a "Functional Reactive Programming" game-engine.<br />
<br />
;[http://hackage.haskell.org/package/bullet Bullet]<br />
:A wrapper for the Bullet physics engine.<br />
<br />
;[http://hackage.haskell.org/package/free-game free-game]<br />
:A GUI/game library based on free monads.<br />
<br />
;[http://hackage.haskell.org/package/FunGEn FunGEn]<br />
:FunGEn (Functional Game Engine) is a platform-independent BSD-licensed 2D game engine based on OpenGL and GLUT. Its light dependencies make it easy to install, however GLUT is reputed to be unsuitable for simultaneous keypresses. As of 2011 it's the only general-purpose game engine, and the quickest way to throw together [https://github.com/haskell-game/fungen/blob/master/examples/hello.hs simple] [https://github.com/haskell-game/fungen/blob/master/examples/pong/pong.hs 2D] [https://github.com/haskell-game/fungen/blob/master/examples/worms/worms.hs games], in Haskell. Example code: [http://joyful.com/fungen/site/example.html A Brief Example]. Forks and patches welcome!<br />
<br />
;[http://projects.haskell.org/game-tree/ game-tree]<br />
:game-tree is a purely functional library for searching game trees - useful for zero-sum two player games.<br />
<br />
;[http://hackage.haskell.org/package/GLFW-b GLFW-b]<br />
:Bindings to GLFW, a free, open source, multi-platform library for creating OpenGL contexts and managing input, including keyboard, mouse, joystick and time.<br />
<br />
;[http://gloss.ouroborus.net/ Gloss]<br />
:An OpenGL abstraction layer supporting game-style main loops.<br />
<br />
;[https://github.com/haskell-game haskell-game]<br />
:A project to make game development with Haskell easier to get started with by providing a suite of libraries for covering all sorts of aspects of game development.<br />
<br />
;[https://github.com/mchakravarty/HaskellSpriteKit Haskell SpriteKit]<br />
:Haskell SpriteKit provides a purely functional interface to the SpriteKit game engine on Apple platforms. SpriteKit is a state-of-the-art engine for 2D games and includes a versatile animation framework and an integrated physics engine. It is easy to use without the need for low-level programming or advanced concepts, such FRP.<br />
<br />
;[http://helm-engine.org/ Helm]<br />
:A functionally reactive game engine inspired by [http://elm-lang.org/ Elm].<br />
<br />
;[http://hackage.haskell.org/package/HGamer3D HGamer3D]<br />
:A game engine for Windows which includes Haskell bindings to a couple of C++ libraries and a Haskell API on top of that. Features include Audio, Joystick, Mouse and Keyboard handling, GUI, Network, Physics, 3D graphics. <br />
:[https://www.youtube.com/watch?v=v_GSbObYRkY Y-Wing flight] is a video of a demonstration of the possibilities of HGamer3D.<br />
<br />
;[http://hackage.haskell.org/cgi-bin/hackage-scripts/package/Hipmunk Hipmunk]<br />
:Hipmunk: A Haskell binding for [http://chipmunk-physics.net/ Chipmunk]. Chipmunk is a fast, simple, portable, 2D physics engine. It is completely self-contained. See also [http://hackage.haskell.org/cgi-bin/hackage-scripts/package/HipmunkPlayground HipmunkPlayground]: a simple OpenGL program that allows you to see some of Hipmunk's functions in action.<br />
<br />
;[https://github.com/asivitz/Hickory Hickory]<br />
:Hickory is not really a game engine. It's more of a collection of tools and abstractions that can be used to make games. It doesn't have opinions and doesn't force you into a particular paradigm.<br />
<br />
;[[Hpysics]]<br />
:Hpysics is a physics engine written using Data Parallel Haskell during Google Summer of Code 2008.<br />
<br />
;[http://hackage.haskell.org/package/hogre hogre]<br />
:Haskell bindings to the excellent OGRE 3D rendering engine. Ogre has been used in commercial games such as Torchlight and several books exist documenting the Ogre API. Ogre uses an MIT license making it compatible with many Haskell libraries.<br />
<br />
;[http://hackage.haskell.org/package/IrrHaskell IrrHaskell]<br />
:Haskell binding to the [http://irrlicht.sourceforge.net/ Irrlicht game engine]. The Irrlicht Engine is an open source high performance realtime 3D engine<br />
<br />
;[http://lambdacube3d.com/ LambdaCube 3D]<br />
:LambdaCube 3D is a domain specific language and library that makes it possible to program GPUs in a purely functional style.<br />
<br />
; [https://github.com/LambdaHack/LambdaHack LambdaHack]<br />
: A game engine library for turn- and grid-based roguelike games, with optional tactical squad combat. Produces both browser and native binary games. You need to specify the content to be procedurally generated and the engine builds the world and runs it. Actively developed, accepting extensions and all kinds of contributions.<br />
<br />
;[http://hackage.haskell.org/package/set-cover set-cover]<br />
:Solver for exact set cover problems. Included examples: [[Sudoku]], [[Mastermind]], [[Nonogram]], Domino tessellation, 8 Queens, Soma Cube, [[Tetris Cube]], Cube of L's, Logika's Baumeister puzzle. Generic algorithm allows to choose between slow but flexible Set from containers package and fast but cumbersome bitvectors.<br />
<br />
=== Unfinished/in-progress game engines/libraries ===<br />
<br />
;[https://github.com/adorablepuppy/CurryDog CurryDog]<br />
:Aims to be a 2d and 3d modular game engine.<br />
<br />
;[https://github.com/keera-studios/gtk-helpers gtk-helpers]<br />
:A collection of auxiliary operations related to Gtk2hs. See also [http://keera.co.uk/blog/2013/03/19/creating-board-games-in-haskell/ Creating board games in Haskell in 100 lines of code]<br />
<br />
;[[HaskGame]]<br />
:An incomplete graphics system abstraction layer.<br />
<br />
; [https://bananu7.github.io/Hate Hate]<br />
:Hate is a small framework for graphical haskell games and applications. It's heavily inspired by Love and aims at similar ease of use, but within the power of Haskell's type and concurrency safety.<br />
<br />
; [https://github.com/shicks/hsgame hsgame]<br />
:A framework for network games<br />
<br />
<br />
[[Category:Games|*]]<br />
[[Category:Applications]]<br />
[[Category:Libraries]]</div>Fa-mlhttps://wiki.haskell.org/index.php?title=99_questions/Solutions/6&diff=6295899 questions/Solutions/62019-07-08T00:08:16Z<p>Fa-ml: Added >>= solution</p>
<hr />
<div>(*) Find out whether a list is a palindrome. A palindrome can be read forward or backward; e.g. (x a m a x).<br />
<br />
<haskell><br />
isPalindrome :: (Eq a) => [a] -> Bool<br />
isPalindrome xs = xs == (reverse xs)<br />
</haskell><br />
<br />
<haskell><br />
isPalindrome' [] = True<br />
isPalindrome' [_] = True<br />
isPalindrome' xs = (head xs) == (last xs) && (isPalindrome' $ init $ tail xs) <br />
</haskell><br />
<br />
Here's one to show it done in a fold just for the fun of it. Do note that it is less efficient then the previous 2 though.<br />
<br />
<haskell><br />
isPalindrome'' :: (Eq a) => [a] -> Bool<br />
isPalindrome'' xs = foldl (\acc (a,b) -> if a == b then acc else False) True input<br />
where<br />
input = zip xs (reverse xs)<br />
</haskell><br />
<br />
Another one just for fun:<br />
<br />
<haskell><br />
isPalindrome''' :: (Eq a) => [a] -> Bool<br />
isPalindrome''' = Control.Monad.liftM2 (==) id reverse<br />
</haskell><br />
<br />
Or even:<br />
<br />
<haskell><br />
isPalindrome'''' :: (Eq a) => [a] -> Bool<br />
isPalindrome'''' = (==) Control.Applicative.<*> reverse<br />
</haskell><br />
<br />
Using <code>>>=</code> instead of <code><*></code>:<br />
<br />
<haskell><br />
isPalindromeM :: (Eq a) => [a] -> Bool<br />
isPalindromeM = reverse >>= (==)<br />
</haskell><br />
<br />
Here's one that does half as many compares:<br />
<br />
<haskell><br />
palindrome :: (Eq a) => [a] -> Bool<br />
palindrome xs = p [] xs xs<br />
where p rev (x:xs) (_:_:ys) = p (x:rev) xs ys<br />
p rev (x:xs) [_] = rev == xs<br />
p rev xs [] = rev == xs<br />
</haskell><br />
<br />
Here's one using foldr and zipWith.<br />
<br />
<haskell><br />
palindrome :: (Eq a) => [a] -> Bool<br />
palindrome xs = foldr (&&) True $ zipWith (==) xs (reverse xs)<br />
palindrome' xs = and $ zipWith (==) xs (reverse xs) -- same, but easier<br />
</haskell><br />
<br />
<br />
<haskell><br />
isPalindrome list = take half_len list == reverse (drop (half_len + (len `mod` 2)) list)<br />
where <br />
len = length list<br />
half_len = len `div` 2<br />
<br />
isPalindrome' list = f_part == reverse s_part<br />
where <br />
len = length list<br />
half_len = len `div` 2<br />
(f_part, s_part') = splitAt half_len list<br />
s_part = drop (len `mod` 2) s_part'<br />
</haskell><br />
<br />
<br />
Using Control.Arrows (&&&) fan out operator.<br />
<br />
With monomorphism restriction:<br />
<br />
<haskell><br />
isPalindrome1 xs = (uncurry (==) . (id &&& reverse)) xs<br />
</haskell><br />
<br />
Point free with no monomorphism restriction:<br />
<br />
<haskell><br />
isPalindrome1 = (uncurry (==) . (id &&& reverse))<br />
</haskell><br />
<br />
[[Category:Programming exercise spoilers]]</div>Fa-mlhttps://wiki.haskell.org/index.php?title=IDEs&diff=62647IDEs2018-11-24T07:21:27Z<p>Fa-ml: Added ghcid</p>
<hr />
<div>The IDE world in Haskell is incomplete, but is in motion. There are many choices. When choosing your IDE, there are the following things to consider.<br />
<br />
== Notable features of interest to consider ==<br />
<br />
This is a list of features that any Haskell IDE could or should have. The IDEs listed below generally support some subset of these features. Please add more to this list if you think of anything. In future this should be expanded into separate headings with more description of how they would desirably work. For a discussion of IDEs there is the [https://groups.google.com/forum/#!forum/haskell-ide haskell-ide mailing list] and the [https://github.com/haskell/haskell-ide haskell-ide repository]<br />
<br />
* Syntax highlighting (e.g. for Haskell, Cabal, Literate Haskell, Core, etc.)<br />
* Macros (e.g. inserting imports/aligning/sorting imports, aligning up text, transposing/switching/moving things around)<br />
* Type information (e.g. type at point, info at point, type of expression)<br />
* IntelliSense/completion (e.g. jump-to-definition, who-calls, calls-who, search by type, completion, etc.)<br />
* Project management (e.g. understanding of Cabal, configuration/building/installing, package sandboxing)<br />
* Interactive REPL (e.g. GHCi/Hugs interaction, expression evaluation and such)<br />
* Knowledge of Haskell in the GHCi/GHC side (e.g. understanding error types, the REPL, REPL objects, object inspection)<br />
* Indentation support (e.g. tab cycle, simple back-forward indentation, whole area indentation, structured editing, etc.)<br />
* Proper syntactic awareness of Haskell (e.g. with a proper parser and proper editor transpositions a la the structured editors of the 80s and Isabel et al)<br />
* Documentation support (e.g. ability to call up documentation of symbol or module, either in the editor, or in the browser)<br />
* Debugger support (e.g. stepping, breakpoints, etc.)<br />
* Refactoring support (e.g. symbol renaming, hlint, etc.)<br />
* Templates (e.g. snippets, Zen Coding type stuff, filling in all the cases of a case, etc.)<br />
<br />
== Open Source ==<br />
<br />
=== [https://github.com/rikvdkleij/intellij-haskell IntelliJ plugin for Haskell] ===<br />
:See [http://www.haskell.org/pipermail/haskell-cafe/2014-October/116567.html the announcement of the plugin] and the [http://en.wikipedia.org/wiki/IntelliJ_IDEA Wikipedia article about IntelliJ].<br />
<br />
=== [http://eclipsefp.github.com/ EclipseFP plugin for Eclipse IDE] ===<br />
[https://jpmoresmau.blogspot.fr/search/label/EclipseFP '''The author, JP Moresmau, is no longer maintaining EclipseFP (since 2015)''']<br />
:Eclipse is an open, extensible IDE platform for "everything and nothing in particular". It is implemented in Java and runs on several platforms. The Java IDE built on top of it has already become very popular among Java developers. The Haskell tools extend it to support editing (syntax coloring, code assist), compiling, and running Haskell programs from within the IDE. In more details, it features:<br />
:* Syntax highlighting and errors/warning highlighting<br />
:* A module browser showing all installed packages, their modules and the contents of the modules (functions, types, etc.)<br />
:* Integration with [http://www.haskell.org/hoogle/ Hoogle]: select an identifier in your code, press F4 and see the results in hoogle<br />
:* Code navigation: from within a Haskell source file, jump to the file where a symbol in declared, or everywhere a symbol is used (type sensitive search, not just a text search)<br />
:* Outline view: quickly jump to definitions in your file<br />
:* Quick fixes on common errors and import management<br />
:* A cabal file editor and integration with Cabal (uses cabal configure, cabal build under the covers), and a graphical view of installed packages<br />
:* Integration with GHCi: launch GHCi inside Eclipse on any module<br />
:* Integration with the GHCi debugger: performs the GHCi debugging commands for you from the standard Eclipse debugging interface<br />
:* Integration with [http://community.haskell.org/~ndm/hlint/ HLint]: gives you HLint warning on building and allows you to quick fix them<br />
:* Integration with [https://github.com/jaspervdj/stylish-haskell Stylish-Haskell]: format your code with stylish-haskell<br />
:* Test support: shows results of test-framework based test suite in a graphical format. HTF support to come soon.<br />
<br />
The plug-ins seem not to be maintained; the github pages says: <br />
Latest commit 2875908 on May 14, 2015 @JPMoresmau JPMoresmau Not maintained<br />
<br />
=== [http://colorer.sourceforge.net/eclipsecolorer/index.html Colorer plugin for Eclipse IDE] ===<br />
:Syntax highlighting in Eclipse can be achieved using the Colorer plugin. This is more light weight than using the EclipseFP plugin which has much functionality but can be messy to install and has sometimes been a bit shaky.<br />
<br />
:Eclipse Colorer is a plugin that enables syntax highlighting for a wide range of languages. It uses its own XML-based language for describing syntactic regions of languages. It does not include support for Haskell by default, but this can be added using the syntax description files attached below.<br />
<br />
:<b>Installation instructions</b><br />
:# Install the Colorer from the update site <code>http://colorer.sf.net/eclipsecolorer/</code> (for more detailed instructions see the project page).<br />
:# Download the Haskell syntax description files in [http://www.haskell.org/wikiupload/1/16/Haskell_Eclipse_Colorer.tar.gz Haskell_Eclipse_Colorer.tar.gz].<br />
:#Extract its contents (haskell.hrc and proto.hrc) into the following directory (overwriting proto.hrc): <code>eclipse_installation_dir/plugins/net.sf.colorer_0.9.9/colorer/hrc</code> (sometimes the wiki seems to create a nesting tar file, so you might have to unpack twise).<br />
:# Finished. A restart of Eclipse might be required. .hs files should open with syntax highlighting.<br />
<br />
:<b>Tips</b><br />
:* If .hs files open with another kind of syntax highlighting check that they are associated with the Colorer Editor (Preferences -> General -> Editors -> File Associations). Or right click on them and choose Open With -> Other -> Colorer Editor.<br />
:* Sometimes the highlighting gets confused. Then it might help to press Ctrl+R and re-colour the editor.<br />
:* Use the Word Completion feature (Shift+Alt+7) as a poor man's content assist.<br />
:* Use the standard External Tools feature in Eclipse to invoke the compiler from inside the IDE.<br />
:* Use the Block selection feature (Shift+Alt+A) to insert/remove line comments on multiple lines at the same time.<br />
:* Some other useful standard Eclipse features include the Open resource command (Ctrl+Shift+R), the File search command (Ctrl+H) and the bookmarks feature (Edit -> Add bookmark). Make sure to check Include in next/prev navigation box (Windows -> Preferences -> General -> Editors -> Text Editors -> Annotations -> Bookmarks).<br />
<br />
=== [[Leksah]] ===<br />
:Leksah is an IDE for Haskell written in Haskell. Leksah is intended as a practical tool to support the Haskell development process. Leksah uses GTK+ as GUI Toolkit with the gtk2hs binding. It is platform independent and should run on any platform where GTK+, gtk2hs and GHC can be installed.<br />
<br />
* http://www.leksah.org/<br />
* https://hackage.haskell.org/package/leksah<br />
* https://github.com/leksah/leksah<br />
<br />
=== [http://kdevelop.org/ KDevelop] ===<br />
:This IDE supports many languages. For Haskell it currently supports project management, syntax highlighting, building (with GHC) & executing within the IDE.<br />
<br />
=== [http://www.vim.org Vim] ===<br />
<br />
This may or may not be up to date. A Vim user should update it.<br />
<br />
:* [https://github.com/begriffs/haskell-vim-now Haskell-vim-now] -- Full-featured Vim config with install script. Supports type inspection, linting, Hoogle, tagging with codex+hasktags, unicode concealing, and refactoring.<br />
:* [http://projects.haskell.org/haskellmode-vim/ Haskell mode for Vim by Claus Reinke] - These plugins provide Vim integration with GHC and Haddock.<br />
:* [https://github.com/scrooloose/syntastic Syntastic] -- An extremely useful Vim plugin which will interact with ghc_mod (when editing a Haskell file) every time the source file is saved to check for syntax and type errors.<br />
:* [http://www.vim.org/scripts/script.php?script_id=2356 SHIM by Lars Kotthoff] -- Superior Haskell Interaction Mode (SHIM) plugin for Vim providing full GHCi integration (requires Vim compiled with Ruby support).<br />
:* [http://www.vim.org/scripts/script.php?script_id=3200 Haskell Conceal] -- shows Unicode symbols for common Haskell operators such as ++ and other lexical notation in Vim window (source file itself remains unchanged).<br />
:* [http://urchin.earth.li/~ian/vim/ by Ian Lynagh]: distinguishes different literal Haskell styles (Vim 7.0 includes a syntax file which supersedes these plugins).<br />
:* There's a [[Literate programming/Vim|copy of lhaskell.vim]] on the Wiki.<br />
:* [https://github.com/MarcWeber/vim-addon-haskell by Marc Weber] -- Vim script-based function/module completion, cabal support, tagging by one command, context completion ( w<tab> -> where ), module outline, etc<br />
:* [http://www.vim.org/scripts/script.php?script_id=1968 Vim indenting mode for Haskell]<br />
:* [https://github.com/ujihisa/neco-ghc neco-ghc] pragma, module, function completion.<br />
:* [https://github.com/eagletmt/ghcmod-vim Ghcmod-vim]<br />
:* [https://github.com/bitc/vim-hdevtools Hdevtools] - gives type information, quicker reloading and more.<br />
<!-- :* [http://blog-mno2.csie.org/blog/2011/11/17/vim-plugins-for-haskell-programmers/ Addition list] with some missing here with screen shots of many of the above. --><br />
<br />
Also: [[Vim]]<br />
<br />
=== [http://www.gnu.org/s/emacs/ Emacs] ===<br />
<br />
See [[Emacs]].<br />
<br />
=== [http://atom.io Atom] ===<br />
<br />
Atom is very similar to Sublime Text 2 (which is now discontinued). A huge [http://atom.io/packages package database] exists and two packages important to haskell developers are:<br />
:* [https://atom.io/packages/language-haskell language-haskell] for haskell syntax highlighting.<br />
:* [https://atom.io/packages/ide-haskell ide-haskell] for cabal-support, linting and ghc-mod utilities like type previewing.<br />
<br />
=== [https://github.com/ndmitchell/ghcid Ghcid] ===<br />
<br />
Not an editor per se, but a barebone IDE that will let you know compilation error any time you save a file. Doesn't integrate with any editor but works well with any of them + a terminal emulator.<br />
<br />
== Commercial ==<br />
<br />
=== [http://haskellformac.com Haskell for Mac] ===<br />
<br />
Haskell for Mac is an easy-to-use integrated programming environment for Haskell on OS X. It is a one-click install of a complete Haskell system, including Haskell compiler, editor, many libraries, and a novel form of interactive <em>Haskell playgrounds</em>. Haskell playgrounds support exploration and experimentation with code. They are convenient to learn functional programming, prototype Haskell code, interactively visualize data, and to create interactive animations.<br />
<br />
Features include the following:<br />
* Built-in Haskell editor with customisable themes, or you can use a separate text editor.<br />
* Autosaving and automatic project versioning.<br />
* Interactive Haskell playgrounds evaluate your code as you type.<br />
* Playground results can be text or images produced by the Rasterific, Diagrams, and Chart packages.<br />
* Add code and multimedia files to a Haskell project with drag'n'drop. <br />
* Haskell binding to Apple's 2D animation and games framework SpriteKit.<br />
<br />
Haskell for Mac requires OS X Yosemite or above.<br />
<br />
=== [https://github.com/SublimeHaskell/SublimeHaskell/ Sublime-Haskell] ===<br />
<br />
Sublime-Haskell is a plugin for the [http://www.sublimetext.com/ Sublime Text Editor]. It is installed through the [https://sublime.wbond.net/ Sublime Package Controller].<br />
<br />
It is built as a plugin to the Sublime text editor, so all the standard editing functionality is there. Here are the Haskell specific features:<br />
* Syntax highlighting and error marking for Haskell and Cabal. Errors provided by interaction with the compiler. The errors are listed in an error pane, and the user can navigate through the errors.<br />
* When working on a project that has a Cabal file, the Cabal file is detected, and the project can be configured, built, run, and tested using Cabal. The Cabal file is automatically detected. This also enhances error reporting, and auto-completion (all exported symbols from the project can then be matched against). Thus, there is good project management support.<br />
* Rescan/build on file change.<br />
* Can use Cabal-dev for sandboxing/pristine builds.<br />
* Prettification/indentation and alignment via Stylish-Haskell.<br />
* Jump to definition, and show information for a definition (using haskell-docs).<br />
* Type display and insertion<br />
* Fast building and type-inference via hdevtools.<br />
* HLint provided by GHC-Mod.<br />
<br />
Thus, Sublime-Haskell satisfies all the requirements listed at the top of the wiki for a baseline Haskell IDE. Sublime-Text is closed source, but the Haskell plugin is open source.<br />
<br />
== See also ==<br />
<br />
* [http://blog.johantibell.com/2011/08/results-from-state-of-haskell-2011.html Results from the State of Haskell, 2011 Survey]. <br />
* [http://nickknowlson.com/blog/2011/09/12/haskell-survey-categorized-weaknesses/ Categorized Weaknesses from the State of Haskell 2011 Survey], which barely touched upon IDEs.<br />
* [[Editors]]<br />
* [[Applications and libraries/Program development#Editor support]]<br />
* [http://code.haskell.org/shim/ Shim]; the aim of the shim (Superior Haskell Interaction Mode) project is to provide better support for editing Haskell code in VIM and Emacs<br />
<br />
== Other IDEs and Editors ==<br />
<br />
The list below is incomplete. Please add to it with whatever you think of. This list should be expanded into sections, as above, with more details, with links to the actual documentation of the described features.<br />
<br />
* Vim — '''PROS:''' Free. Works on Windows. Works in terminal. Decent alignment support. Tag-based completion and jumps. Very good syntax highlighting, flymake (via Syntastic), Cabal integration, Hoogle. Documentation for symbol at point '''CONS:''' Arcane, difficult for new users. Some complain of bad indentation support.<br />
* [http://www.haskell.org/haskellwiki/Haskell_mode_for_Emacs Emacs]— '''PROS:''' Free. Works on Windows. Works in terminal. Decent alignment, indentation, syntax highlighting. Limited type information (type and info of name at point). Cabal/GHC/GHCi awareness and Haskell-aware REPL. Completion and jump-to-definition (via ETAGS). Documentation of symbol at point. Hoogle. Documentation for symbol at point. Flymake (error checking on the fly). '''CONS:''' Arcane, difficult for new users.<br />
* Sublime — '''PROS:''' Works on Windows. '''CONS:''' Poor alignment support (though [http://www.reddit.com/r/haskell/comments/ts8fi/haskell_ides_emacs_vim_and_sublime_oh_my_opinions/c4pair1 there are packages] to do indentation a little better). Proprietary.<br />
* [[Yi]] — '''PROS:''' Written in Haskell. Works in terminal. '''CONS:''' Very immature, lacking features. Problems building generally, especially on Windows.<br />
* [http://www.haskell.org/haskellwiki/Leksah Leksah] — '''PROS:''' Syntax highlighting. Understands Cabal, Module browser, dependency knowledge, documentation display inside the IDE, jump-to-definition, flymake (error checking on the fly), limited evaluation of snippets, scratch buffer. Autocompletion. Not an arcane interface a la Emacs/Vim. '''CONS:''' Doesn't have a decent REPL. Are there any other cons? — This should be moved to the section above.<br />
* [[Editors | Other Editors]<br />
* [http://www.cs.kent.ac.uk/projects/heat/ HEAT:] An Interactive Development Environment for Learning & Teaching Haskell<br />
* [http://www.geany.org/ Geany] '''PROS:''' Free. Works on Windows. Syntax highlighting, REPL. '''CONS:''' After using it for a while, Geany freezes quite often.<br />
<br />
== Outdated ==<br />
<br />
* [http://web.archive.org/web/20110726153330/http://hoovy.org/HaskellXcodePlugin/ plugin for Xcode] (links to the web archive)<br />
<br />
=== [http://www.haskell.org/haskellwiki/HIDE hIDE] ===<br />
:hIDE is a GUI-based Haskell IDE written using gtk+hs. It does not include an editor but instead interfaces with NEdit, vim or GNU emacs.<br />
<br />
=== [http://www.haskell.org/haskellwiki/HIDE hIDE-2] ===<br />
:Through the dark ages many a programmer has longed for the ultimate tool. In response to this most unnerving craving, of which we ourselves have had maybe more than our fair share, the dynamic trio of #Haskellaniacs (dons, dcoutts and Lemmih) hereby announce, to the relief of the community, that a fetus has been conceived: ''hIDE - the Haskell Integrated Development Environment''. So far the unborn integrates source code recognition and a chameleon editor, resenting these in a snappy gtk2 environment. Although no seer has yet predicted the date of birth of our hIDEous creature, we hope that the mere knowledge of its existence will spread peace of mind throughout the community as oil on troubled waters. See also: [[HIDE/Screenshots of HIDE]] and [[HIDE]]<br />
<br />
=== [http://web.archive.org/web/20060213161530/http://www.students.cs.uu.nl/people/rjchaaft/JCreator/ JCreator with Haskell support] ===<br />
: <b>N.B. The link above is to the Wayback Machine (Web Archive); it seem that JCreator is no longer supported.</b><br />
:JCreator is a highly customizable Java IDE for Windows. Features include extensive project support, fully customizable toolbars (including the images of user tools) and menus, increase/decrease indent for a selected block of text (tab/shift+tab respectively). The Haskell support module adds syntax highlighting for Haskell files and WinHugs, hugs, a static checker (if you double click on the error message, JCreator will jump to the right file and line and highlight it yellow) and the Haskell 98 Report as tools. Platforms: Win95, Win98, WinNT and Win2000 (only Win95 not tested yet). Size: 6MB. JCreator is a trademark of Xinox Software; Copyright &copy; 2000 Xinox Software. The Haskell support module is made by Rijk-Jan van Haaften.<br />
<br />
=== [[haste]] - Haskell TurboEdit ===<br />
:haste - Haskell TurboEdit - was an IDE for the functional programming language Haskell, written in Haskell.<br />
<br />
=== [http://www.haskell.org/visualhaskell Visual Haskell] ===<br />
:Visual Haskell is a complete development environment for Haskell software, based on Microsoft's [http://www.microsoft.com/visualstudio/en-us Microsoft Visual Studio] platform. Visual Haskell integrates with the Visual Studio editor to provide interactive features to aid Haskell development, and it enables the construction of projects consisting of multiple Haskell modules, using the Cabal building/packaging infrastructure.<br />
<br />
=== [http://www.cs.kent.ac.uk/projects/vital/ Vital] ===<br />
:Vital is a visual programming environment. It is particularly intended for supporting the open-ended, incremental style of development often preferred by end users (engineers, scientists, analysts, etc.).<br />
<br />
=== [http://www.cs.kent.ac.uk/projects/pivotal/ Pivotal] ===<br />
:Pivotal 0.025 is an early prototype of a Vital-like environment for Haskell. Unlike Vital, however, Pivotal is implemented entirely in Haskell. The implementation is based on the use of the hs-plugins library to allow dynamic compilation and evaluation of Haskell expressions together with the gtk2hs library for implementing the GUI.<br />
<br />
=== [https://www.fpcomplete.com/business/haskell-center/overview/ FP Haskell Center] ===<br />
<br />
:FP Complete has developed a commercial Haskell IDE. (Now [https://www.fpcomplete.com/blog/2015/10/retiring-fphc retired]).<br />
<br />
: It's in the cloud, and comes with all of the libraries on Stackage ready to go. (Basically, the Haskell Platform on steroids.) It's "in the cloud," which has its pros and cons.<br />
<br />
: The standard IDE is in your browser, and has integration with Git and Github. Emacs, Sublime and Vim support will be released soon. One particularly cool feature is that you can spin up temporary web servers to test out the Haskell-powered website you might be coding up. It's really easy, and you can pay for FP Complete to host your permanent application, too.<br />
<br />
: There's a free trial, with free academic licenses and paid commercial licenses. There will be "personal" licenses in a few weeks (from early Sept 2013) as well, since the commercial pricing is a bit steep for hobbyists.<br />
<br />
: Some of the features:<br />
<br />
* Auto-completion.<br />
* Hoogle searching of all of Stackage.<br />
* Hoogling in the context of a module and its imports.<br />
* Live typechecking/recompiling / jump to error.<br />
* Hlint suggestions.<br />
* Jump to definition.<br />
* Auto-removal of unnecessary imports.<br />
* Get type of any identifier (globally or locally defined).<br />
* Show documentation of any symbol (via hoogle), or open haddocks.<br />
* Refactoring.<br />
* Build project, run project.<br />
* Auto-code formatting.<br />
* Run a temporary web service for testing web apps.<br />
* Deploy project to an Amazon instance.</div>Fa-mlhttps://wiki.haskell.org/index.php?title=FRP_explanation_using_reactive-banana&diff=61325FRP explanation using reactive-banana2016-12-16T18:02:32Z<p>Fa-ml: Undo revision 61322 by Fa-ml same</p>
<hr />
<div>This is an attempt to explain Functional Reactive Programming (FRP) enough to give a reader with no previous exposure to FRP an intuition what FRP is about. After reading this you should hopefully understand enough of FRP to understand the [http://www.haskell.org/haskellwiki/Reactive-banana reactive-banana] examples.<br />
<br />
FRP has certain terms such as behavior, event and time-varying that can be confusing for people unfamiliar with it. I'll avoid these terms at first and will focus on spreadsheets and a generalization of spreadsheet cells (which I will call boxes). Later, once the most important concepts are explained, reactive-banana syntax will be introduced along with an example that demonstrates how to work with behaviors and events in reactive-banana. Finally some theory about time-varying functions and how events and behaviors can be implemented using pure functions by making time explicit should provide the necessary background to understand reactive-banana's haddock comments.<br />
<br />
The version of reactive-banana used here is [http://hackage.haskell.org/package/reactive-banana-0.8.0.0 0.8.0.0].<br />
<br />
== Reactive programming for the masses: the spreadsheet ==<br />
<br />
Spreadsheets are something we all (for certain values of we) know about. Let's talk about a typical, simplified, spreadsheet. We have a list of products that we sell and want to compute their price with the Value Added Tax (VAT) added. We might have cells A1 to A10 contain the raw prices of our products and cell B1 contain the current VAT rate (say 19 for a 19% VAT). In cells C1 to C10 we'd like to see the prices including VAT.<br />
<br />
In cell C1 we'd have a formula: <tt>=A1*(1+B1/100)</tt>, in cell C2 <tt>=A2*(1+B1/100)</tt>, etc. So if A1 contains $100 C1 would contain $119.<br />
<br />
But what if the government, in its eternal quest to reduce the budget deficit, raises the VAT rate? We'd adjust cell B1, just change it to 20. And like magic all the C cells are updated.<br />
<br />
Though this may seem mundane what we've just seen is actually a very good example of reactive programming. We didn't tell the C cells to update; they updated on their own because a value they depend on changed.<br />
<br />
== From cells to boxes: generalizing the spreadsheet ==<br />
<br />
Spreadsheets are nice, but if we want to truly get a feel for FRP we'll have to think beyond them. If we look at a spreadsheet at an abstract level it pretty much consists of cells of two types: value cells (<tt>19</tt>) and formula cells (<tt>=A1*(1+B1/100)</tt>). Let's lose the reference to spreadsheets and talk about boxes.<br />
<br />
Say, for now, that there are two kinds of boxes: formula boxes and value boxes. Both support a &ldquo;get&rdquo; operation that returns a value. Value boxes additionally support a &ldquo;set&rdquo; operation that sets the value.<br />
<br />
Formula boxes can contain any kind of pure function. They can also refer to the values of other boxes (both formula and value boxes). Value boxes don't have a function inside them, they have a value.<br />
<br />
The translation of our VAT spreadsheet would be something like a formula box ''fIncl1'' containing the expression <tt>get(vExcl1) * (1 + get(vVat) / 100)</tt>. This expression uses two value boxes: ''vExcl1'' and ''vVat''.<br />
<br />
We could also write ''fIncl1'' using a helper formula box ''fVat''. Let ''fVat'' have the formula <tt>1 + get(vVat) / 100</tt> and ''fIncl1'' have the formula <tt>get(vExcl1) * get(vVat)</tt>. I'll use <tt>:=</tt> for this kind of definition, the <tt>:=</tt> is there to remind you that this isn't Haskell.<br />
<br />
It's important to note that any kind of value may be put into value boxes, including IO actions and functions.<br />
<br />
Try doing this with a spreadsheet: <tt>fIncls := [get(ve) * get(vVat) | ve <- vExcls]</tt>. Or this: <tt>fIncl1 := apply(get(vVatFunc), get(vExcl1))</tt>.<br />
<br />
If you're wondering why I'm not using Haskell syntax, it's to focus on the meaning of boxes rather than what the functions and combinators mean. That said, this pseudo-imperative syntax is on its way out as it's getting too clunky (that <tt>apply</tt> function is really just ugly). For a quick peek ahead the last few examples would be something like this in reactive-banana:<br />
<br />
<haskell>fIncls = map (\ve -> (*) <$> ve <*> fVat) vExcls<br />
fIncl1 = fVatFunc <*> vExcl1</haskell><br />
<br />
== Events ==<br />
<br />
Let's say we want to build the worlds worst synthesizer. We have 7 buttons: &ldquo;a&rdquo;, &ldquo;b&rdquo;, &ldquo;c&rdquo;, &ldquo;d&rdquo;, &ldquo;e&rdquo;, &ldquo;f&rdquo; and &ldquo;g&rdquo;. Our output is generated by sampling a box twice per second and playing the frequency in the box until the next sample is taken.<br />
<br />
This can't be expressed with the crude formula and value boxes system we've had so far. There is no way to express key presses in that system, a key press isn't like changing a value, it's something that occurs on a specific point in time but after it occurs it's forgotten (your keyboard doesn't remember key strokes, at least mine doesn't).<br />
<br />
In this new system we'll forget about formula boxes and value boxes and introduce event boxes. Event boxes are like formula boxes in that they can refer to the value of other boxes. Event boxes can also react to events.<br />
<br />
Events can be thought of like signals in something like D-Bus. Multiple things (event boxes) can listen to them and do something once a specific event is fired (triggered).<br />
<br />
Every event has a value associated with it. Sometimes the value isn't important because the fact that the event has occurred is what's interesting but often we do want to know the value.<br />
<br />
Events come in streams. When we say event box ''b1'' changes to the value of event ''e1'' when it receives that event we're actually saying that whenever an event from the stream of events we colloquially call ''e1'' comes ''b1'' changes to the value of that event.<br />
<br />
Yes, that's confusing so I'll try to be precise. Just remember that when I refer to something like ''e1'' when defining an event box it's always to a stream of events, never a specific event.<br />
<br />
If you're puzzled by the stream just think of it as an acknowledgement that a certain kind of event can occur multiple times. It actually goes a lot deeper than that, involving those confusing <tt>[(t, e)]</tt> types, but for now just remembering that a kind of event can occur multiple times with possibly different values is good enough.<br />
<br />
Events have values and we can use that to chose to do something only for events with some value. So not only can we determine which streams of events we'll do something with when defining an event box, we can also determine for what values of events we'll do something.<br />
<br />
For example if we have an event that directly sets our synthesizer frequency we can apply a filter that only allows events with frequencies that are pleasant to the human ear.<br />
<br />
== Some reactive-banana syntax ==<br />
<br />
Expressing event handling with the pseudo-code I've used before is tricky and gets near impossible soon. So it's a good thing that once you've understood or at least got a basic idea of the concepts of event streams and event boxes the syntax of reactive-banana starts to make sense. In this section I'll explain the most fundamental functions and operators.<br />
<br />
If you're reading the [http://hackage.haskell.org/package/reactive-banana-0.5.0.0 reactive-banana 0.5 haddocks] there are a few things to keep in mind. The first is that what I've called an event box in the previous section is called a Behaviour in reactive-banana. To avoid confusion I'll stop using the term event box from here on.<br />
<br />
In the reactive-banana haddocks you'll find a lot of references to time-varying functions and lists involving time variables. Just ignore those, they're important but we'll get to them later. As a general rule just ignore what you don't understand.<br />
<br />
You'll also notice a <hask>t</hask> parameter on the <hask>Event</hask> and <hask>Behavior</hask> types. It's basically similar to the <hask>s</hask> parameter for <hask>STRef</hask>, it's a trick to use the type system to prevent constructs that would result in undefined or incorrect behavior. Just ignore it.<br />
<br />
For understanding the next sections you'll need to know about a basic subset of reactive-banana which I'll explain here. First up: event streams.<br />
<br />
=== Events ===<br />
<br />
Event streams are represented by the type Event in reactive-banana. The type <hask>Event t Int</hask> means a stream of events carrying Int values.<br />
<br />
There are three basic things you can do with just event streams. You can transform the events in them, you can filter in events in them and you can combine the event streams.<br />
<br />
Transforming an event stream means changing the values carried by the events in them. As this is ''Functional'' Reactive Programming the streams themselves are not changed. When you transform a stream you create a new stream. Whenever an event in the old stream is fired an event in the new stream is also fired, but with a different value.<br />
<br />
Transforming an event stream is done primarily by good old fmap. The expression <hask>show `fmap` eInt</hask> (or with the (<hask><$></hask>) operator <hask>show <$> eInts</hask>) with ''eInt'' having the type <hask>Event t Int</hask> creates a new event stream of the type <hask>Event String</hask> with the int in every event in the original stream being a string in the new stream.<br />
<br />
To replace the value of an event (if the event doesn't carry a useful value) just use (<hask><$</hask>): <hask>"MOO!" <$ eWhatever</hask> causes every value in the stream eWhatever to be replaced by MOO!. Like (<hask><$></hask>) this is an operator from Control.Applicative.<br />
<br />
Filtering is done using the <hask>filterE</hask> function. When you filter an event stream you create a new event stream with the same associated values but which doesn't contain all the events from the original stream. To only deal with events with positive integers you can create a filtered stream using <hask>filterE (>= 0) eInt</hask>.<br />
<br />
Combining event streams creates a new event stream with all the events from both streams. So if you combine ''eOne'' and ''eTwo'' into ''eThree'' there will be an event in ''eThree'' for every event in ''eOne'' and for every event in ''eTwo''.<br />
<br />
Combining is done with the union function: <hask>eThree = eOne `union` eTwo</hask>. Beware however that when events come in at the same time things can get a little tricky, you'd have to wonder in what order the events are processed. Reactive-banana contains several functions to handle simultaneous events. For the purpose of this page we'll do the easiest thing and ignore simultaneous events. In real world code you would need to think about it.<br />
<br />
=== Behaviors ===<br />
<br />
To create a behavior (event box) in reactive-banana you'll typically use one of two functions: <hask>stepper</hask> and <hask>accumB</hask>. Both work with an initial value and an event stream. The difference is that when an event occurs <hask>stepper</hask> changes the value of the behavior to the value in the event while <hask>accumB</hask> applies the function in the event to the value of the behavior.<br />
<br />
<haskell>eNewVal :: Event t Int<br />
bSet :: Behavior t Int<br />
bSet = stepper 0 eNewVal<br />
<br />
eUpdater :: Event t (Int -> Int)<br />
bUpdated :: Behavior t Int<br />
bUpdated = accumB 0 eUpdater</haskell><br />
The expression <hask>bSet = stepper 0 eNewVal</hask> creates a behavior named ''bSet'' with initially value 0. Once an event from the ''eNewVal'' stream comes in the value of ''bInt'' changes to the value in that event. So if an event comes in with value 2 the value of bSet becomes 2.<br />
<br />
On the other hand the expression <hask>bUpdated = accumB 0 eUpdater</hask> makes ''bUpdated'' a behavior with initially the value 0 but which gets updated (modified) whenever an event comes in. If an event comes in with value (+1) (a slice, so <hask>\x -> x + 1</hask>) and the current value of ''bUpdated'' is 1 the new value becomes 2.<br />
<br />
That's basically it for behaviors. Well, there's a third way to create behaviors: using <hask>pure</hask>. To create a behavior with the value 1 which doesn't change at all use <hask>pure 1</hask>. In case you didn't know, for applicative functors (which behaviors are) <hask>pure</hask> is what <hask>return</hask> is for monads.<br />
<br />
To create a behavior that's depends on old behaviors (<hask>f3 := get(f1) + get(f2)</hask> in our old formula box syntax) we have to use applicative functor functions in reactive-banana. There is unfortunately no option to use monad syntax. To express that the value of ''b3'' is the sum of the value of ''b1'' and the value of ''b2'' we write: <hask>b3 = (+) <$> b1 <*> b2</hask>.<br />
<br />
== Example: the worlds worst synthesizer ==<br />
<br />
Now for an example. We'd like to create a synthesizer. The synthesizer will use our keyboard for input, which we notice through a stream of events called ''eKey'' with as associated value a Char containing the key that was pressed. Something outside our program (and scope of discussion) samples the behavior ''bNote'' every 100ms and plays the tone currently in there until the next sample time.<br />
<br />
To avoid getting caught up in music theory (read: I'm lazy and can't be bothered to look up tone frequencies) the note to play is expressed as an algebraic data type.<br />
<br />
<haskell>type Octave = Int<br />
data Pitch = PA | PB | PC | PD | PE | PF | PG<br />
data Note = Note Octave Pitch<br />
<br />
-- Type signature for the key event, it comes from outside our<br />
-- system.<br />
eKey :: Event t Char</haskell><br />
You'll notice the octave. To change the octave we'll use the '-' and '+' keys. To set the pitch we'll use the 'a'..'g' keys on the keyboard. Never mind that it's really annoying to play with those keys as they're scattered all over the keyboard, this is about the FRP logic not practicality.<br />
<br />
Those chars in the ''eKey'' event stream need to be translated to pitches. Here's one way to do that.<br />
<br />
<haskell>ePitch :: Event t Pitch<br />
ePitch = (PA <$ filterE (=='a') eKey) `union`<br />
(PB <$ filterE (=='b') eKey) `union`<br />
... <br />
(PG <$ filterE (=='g') eKey)</haskell><br />
The &ldquo;trouble&rdquo; here is that we're filtering the stream multiple times, not very efficient. Here's a better way.<br />
<br />
<haskell>table = [('a', PA), ('b', PB), ..., ('g', PG)]<br />
ePitch = filterJust $ (\e -> lookup e table) <$> eKey</haskell><br />
The <hask>filterJust</hask> function is a simple helper in reactive-banana. It filters out <hask>Nothing</hask> events and returns the value inside the <hask>Just</hask> constructor for <hask>Just</hask> events. To get ''ePitch'' we first look up the characters in the translation table and then remove all events who's chars aren't in the table, removing the <hask>Just</hask> wrapper from events who's chars are in the table at the same time.<br />
<br />
The ''bNote'' behavior will not use these events directly, instead ''bOctave'' and ''bPitch'' will each store part of the note and ''bNote'' will combine the information.<br />
<br />
<haskell>eOctChange :: Char -> Maybe (Octave -> Octave)<br />
eOctChange c = case c of<br />
'+' -> Just (+1)<br />
'-' -> Just (subtract 1)<br />
_ -> Nothing<br />
<br />
bOctave :: Behavior t Octave<br />
bOctave = accumB 0 $ filterJust (eOctChange <$> eKey)<br />
<br />
bPitch :: Behavior t Pitch<br />
bPitch = stepper PC ePitch<br />
<br />
bNote :: Behavior t Note<br />
bNote = Note <$> bOctave <*> bPitch</haskell><br />
If you understand what's going on here you should have a basic idea of what FRP is in practice. There are of course considerations in the real world that we've skipped over here, such as how to get the keyboard event and how to play the sounds. To get a better idea of what FRP in the real world looks take a look at the [http://www.haskell.org/haskellwiki/Reactive-banana/Examples reactive-banana examples], they should be easy to follow.<br />
<br />
When following those examples you'll come across the (<hask><@</hask>) and (<hask><@></hask>) operators. I'll give a short introduction here to make it easier to understand the examples. The (<hask><@</hask>) operator is used like this: <hask>e2 = b1 <@ e1</hask>, if an event in stream ''e1'' comes in the value of that event is replaced in the ''e2'' stream by whatever value is in ''b1'' at the time. The (<hask><@></hask>) operator is used in much the same way, but it doesn't replace the value from ''e1'' outright but uses it to compute a new value.<br />
<br />
<haskell>bOne :: Behavior t Int<br />
bOne = pure 1<br />
<br />
bPlusOne :: Behavior t (Int -> Int)<br />
bPlusOne = pure (+1)<br />
<br />
eAlwaysOne, ePlusOne :: Event t Int<br />
eAlwaysOne = bOne <@ eWhatever<br />
ePlusOne = bPlusOne <@> eInt</haskell><br />
<br />
== Time-varying values and functions ==<br />
<br />
If you've read about FRP before you're likely to have come across the term &ldquo;time-varying function&rdquo;. This sounds difficult, but once you understand the basics of behaviors and events it's really no big deal.<br />
<br />
Here's the clue: a behavior contains a value, but the value can change. Therefore at different points in time a behavior can have different values. So we could say that a behavior has a value that varies in time.<br />
<br />
We could also throw away the concept of boxes and say a behavior ''is'' a value that varies in time. This is more correct, those boxes are helpful as teaching concepts but once we talk directly about time they are no longer needed.<br />
<br />
So, a time-varying value is simply a behavior as behaviors can have different values at different points in time. A time-varying function is also just a behavior, one where the value is a function (functional programming 101: the clue to every riddle is that functions are values).<br />
<br />
To go further down the rabbit hole a time-varying value can actually be thought of as a function by making time explicit. If a behavior has value 1 up to the 30th's second and from that point forward value 2 we could express the behavior as: <hask>\t -> if t < 30 then 1 else 2</hask>. This is important: by making time explicit we can reason about behaviors as if they were pure functions. While in practice we're dealing with applicative functors (or in other libraries monads or arrows) we can think of behaviors as pure functions.<br />
<br />
Real world behaviors aren't as simple as from 30 seconds onwards change to value 2. They interact with events. So to express such behaviors as pure functions events need to be expressed in a way that works for pure functions. This is where the <hask>[(t,e)]</hask> type comes in. We can see events as a list of values at certain points in time, for example <hask>[(10, 1), (20, 2), (30, 3)]</hask> for events that occur on second 10, 20 and 30 with values 1, 2 and 3 respectively.<br />
<br />
When viewing events in such a way it becomes easy to create a behavior that changes to whatever value was last:<br />
<br />
<haskell>type Time = Int<br />
stepped :: [(Time, Int)] -> Time -> Int<br />
stepped es t = case takeWhile (\(t', _) -> t' < t) es of <br />
[] -> 0 <br />
xs -> snd (last xs)</haskell><br />
For once this is actually runnable code. If we invoke it as <hask>stepped [(10,1),(20,1),(30,1)] 2</hask> the result is 0, if we invoke it as <hask>stepped [(10,1),(20,1),(30,1)] 12</hask> the result is 1, as expected.<br />
<br />
Stepped sounds a lot like stepper and we can create that function by making a few small adjustments.<br />
<br />
<haskell>type Time = Int<br />
stepper :: a -> [(Time, a)] -> (Time -> a)<br />
stepper d es = \t -> case takeWhile (\(t', _) -> t' < t) es of<br />
[] -> d<br />
xs -> snd (last xs)</haskell><br />
If you understand this bit, why behaviors and events can be expressed by making time explicit you have a good intuition of what FRP is.<br />
<br />
== Making the example runnable ==<br />
<br />
After I wrote this page I got questions about how to actually run the reactive-banana examples. Here's a big block of code that can be pasted into a file and run:<br />
<br />
<haskell>module Main where<br />
<br />
import Data.Char (toUpper)<br />
import Control.Monad (forever)<br />
import System.IO (BufferMode(..), hSetEcho, hSetBuffering, stdin)<br />
import Reactive.Banana<br />
import Reactive.Banana.Frameworks.AddHandler<br />
import Reactive.Banana.Frameworks<br />
<br />
type Octave = Int<br />
<br />
data Pitch = PA | PB | PC | PD | PE | PF | PG<br />
deriving (Eq, Enum)<br />
<br />
-- Mapping between pitch and the char responsible for it.<br />
pitchChars :: [(Pitch, Char)]<br />
pitchChars = [(p, toEnum $ fromEnum 'a' + fromEnum p) |<br />
p <- [PA .. PG]]<br />
<br />
-- Reverse of pitchChars<br />
charPitches :: [(Char, Pitch)]<br />
charPitches = [(b, a) | (a, b) <- pitchChars]<br />
<br />
data Note = Note Octave Pitch<br />
<br />
instance Show Pitch where<br />
show p = case lookup p pitchChars of<br />
Nothing -> error "cannot happen"<br />
Just c -> [toUpper c]<br />
<br />
instance Show Note where<br />
show (Note o p) = show p ++ show o<br />
<br />
-- Filter and transform events at the same time.<br />
filterMapJust :: (a -> Maybe b) -> Event t a -> Event t b<br />
filterMapJust f = filterJust . fmap f<br />
<br />
-- Change the original octave by adding a number of octaves, taking<br />
-- care to limit the resulting octave to the 0..10 range.<br />
changeOctave :: Int -> Octave -> Octave<br />
changeOctave d = max 0 . min 10 . (d+)<br />
<br />
-- Get the octave change for the '+' and '-' chars.<br />
getOctaveChange :: Char -> Maybe Int<br />
getOctaveChange c = case c of<br />
'+' -> Just 1<br />
'-' -> Just (-1)<br />
_ -> Nothing<br />
<br />
makeNetworkDescription :: Frameworks t<br />
=> AddHandler Char<br />
-> Moment t ()<br />
makeNetworkDescription addKeyEvent = do<br />
eKey <- fromAddHandler addKeyEvent<br />
let<br />
eOctaveChange = filterMapJust getOctaveChange eKey<br />
bOctave = accumB 3 (changeOctave <$> eOctaveChange)<br />
ePitch = filterMapJust (`lookup` charPitches) eKey<br />
bPitch = stepper PC ePitch<br />
bNote = Note <$> bOctave <*> bPitch<br />
eNoteChanged <- changes bNote<br />
reactimate' $ fmap (\n -> putStrLn ("Now playing " ++ show n))<br />
<$> eNoteChanged<br />
<br />
main :: IO ()<br />
main = do<br />
(addKeyEvent, fireKey) <- newAddHandler<br />
network <- compile (makeNetworkDescription addKeyEvent)<br />
actuate network<br />
hSetEcho stdin False<br />
hSetBuffering stdin NoBuffering<br />
forever (getChar >>= fireKey)</haskell><br />
If you compare this to the previous example you'll notice some changes in the events and behaviors. This version is more real-world, there are bounds checks and some abstraction (<hask>filterMapJust</hask>).<br />
<br />
The parts answering the question &ldquo;how to run it?&rdquo; are all in <hask>makeNetworkDescription</hask> and <hask>main</hask>. In reactive-banana you first create a description of an event network, then compile that network, enable it and call your normal Haskell event loop. At least, that's the case when you don't use a GUI framework with reactive-banana integration, if you use the wx integration for reactive-banana the event loop is already written for you and some other details are different. See the [http://www.haskell.org/haskellwiki/Reactive-banana/Examples examples].<br />
<br />
All the events and behaviors live in what reactive-banana calls an event network. It's not possible to use behaviors outside this network, you can't for example see inside a behavior from IO code. You can use events though and that's how you couple the FRP stuff inside the event network to the outside world.<br />
<br />
To create an event that you can fire from outside the event network use <hask>newAddHandler</hask> in the IO monad. It gives you two things, an <hask>AddHandler</hask> value and an IO action that takes a value and fires an event with that value. By passing the <hask>AddHandler</hask> value to <hask>fromAddHandler</hask> (inside the <hask>NetworkDescription</hask> monad) you'll get an event stream which you can use in a normal fashion.<br />
<br />
To handle output events use <hask>reactimate</hask>, pass it an event stream containing IO actions and whenever an event from that stream occurs the action is executed. You'll pretty much always want to use <hask>reactimate</hask> with (<hask><$></hask>)/<hask>fmap</hask> to generate those IO actions.<br />
<br />
Once the network description is complete you can compile it. This gives you back an <hask>EventNetwork</hask> value. You can start the <hask>EventNetwork</hask> with <hask>actuate</hask>. This sets things up so that events can actually be received.<br />
<br />
In our roll-your-own program we'll use <hask>getChar</hask> (after turning off echo and buffering on the standard input stream) to receive characters. When a character is received the ''bNote'' is updated and a message is printed with the new value (actually playing a tone appears to involve more code than I'd like to include here).<br />
<br />
Wait? Didn't I say we can't actually observe the value of a behavior? So how do we know which note to play? Turns out reactive-banana has a nice little function called <hask>changes</hask>. When used on a behavior it returns an event stream which contains the new values whenever the behavior is updated. This event stream is passed to <hask>reactimate</hask> to trigger the prints.<br />
<br />
== A broader view of FRP ==<br />
<br />
FRP is a field which is currently in active development, many different approach are being tried and no real standard has been found yet. The [http://hackage.haskell.org/packages/archive/pkg-list.html#cat:frp FRP category on hackage] has a lot of different packages with varying approaches to implementing FRP. Some focus on applicative functors, some on monads and others on arrows.<br />
<br />
Semantics can be subtly or not-so-sublty different between FRP libraries and sometimes naming is different as well (for example signal instead of event).<br />
<br />
In this page I've tried to explain FRP using one specific library (reactive-banana). While this makes things simpler for getting an idea of FRP it can give some wrong impressions due to conflating the limitations of reactive-banana and that of FRP in general.<br />
<br />
[[Category:FRP]] [[Category:Tutorials]]</div>Fa-mlhttps://wiki.haskell.org/index.php?title=FRP_explanation_using_reactive-banana&diff=61324FRP explanation using reactive-banana2016-12-16T18:01:51Z<p>Fa-ml: Undo revision 61323 by Fa-ml ok I am not the brightest bulb in the pack</p>
<hr />
<div>This is an attempt to explain Functional Reactive Programming (FRP) enough to give a reader with no previous exposure to FRP an intuition what FRP is about. After reading this you should hopefully understand enough of FRP to understand the [http://www.haskell.org/haskellwiki/Reactive-banana reactive-banana] examples.<br />
<br />
FRP has certain terms such as behavior, event and time-varying that can be confusing for people unfamiliar with it. I'll avoid these terms at first and will focus on spreadsheets and a generalization of spreadsheet cells (which I will call boxes). Later, once the most important concepts are explained, reactive-banana syntax will be introduced along with an example that demonstrates how to work with behaviors and events in reactive-banana. Finally some theory about time-varying functions and how events and behaviors can be implemented using pure functions by making time explicit should provide the necessary background to understand reactive-banana's haddock comments.<br />
<br />
The version of reactive-banana used here is [http://hackage.haskell.org/package/reactive-banana-0.8.0.0 0.8.0.0].<br />
<br />
== Reactive programming for the masses: the spreadsheet ==<br />
<br />
Spreadsheets are something we all (for certain values of we) know about. Let's talk about a typical, simplified, spreadsheet. We have a list of products that we sell and want to compute their price with the Value Added Tax (VAT) added. We might have cells A1 to A10 contain the raw prices of our products and cell B1 contain the current VAT rate (say 19 for a 19% VAT). In cells C1 to C10 we'd like to see the prices including VAT.<br />
<br />
In cell C1 we'd have a formula: <tt>=A1*(1+B1/100)</tt>, in cell C2 <tt>=A2*(1+B1/100)</tt>, etc. So if A1 contains $100 C1 would contain $119.<br />
<br />
But what if the government, in its eternal quest to reduce the budget deficit, raises the VAT rate? We'd adjust cell B1, just change it to 20. And like magic all the C cells are updated.<br />
<br />
Though this may seem mundane what we've just seen is actually a very good example of reactive programming. We didn't tell the C cells to update; they updated on their own because a value they depend on changed.<br />
<br />
== From cells to boxes: generalizing the spreadsheet ==<br />
<br />
Spreadsheets are nice, but if we want to truly get a feel for FRP we'll have to think beyond them. If we look at a spreadsheet at an abstract level it pretty much consists of cells of two types: value cells (<tt>19</tt>) and formula cells (<tt>=A1*(100+B1/100)</tt>). Let's lose the reference to spreadsheets and talk about boxes.<br />
<br />
Say, for now, that there are two kinds of boxes: formula boxes and value boxes. Both support a &ldquo;get&rdquo; operation that returns a value. Value boxes additionally support a &ldquo;set&rdquo; operation that sets the value.<br />
<br />
Formula boxes can contain any kind of pure function. They can also refer to the values of other boxes (both formula and value boxes). Value boxes don't have a function inside them, they have a value.<br />
<br />
The translation of our VAT spreadsheet would be something like a formula box ''fIncl1'' containing the expression <tt>get(vExcl1) * (1 + get(vVat) / 100)</tt>. This expression uses two value boxes: ''vExcl1'' and ''vVat''.<br />
<br />
We could also write ''fIncl1'' using a helper formula box ''fVat''. Let ''fVat'' have the formula <tt>1 + get(vVat) / 100</tt> and ''fIncl1'' have the formula <tt>get(vExcl1) * get(vVat)</tt>. I'll use <tt>:=</tt> for this kind of definition, the <tt>:=</tt> is there to remind you that this isn't Haskell.<br />
<br />
It's important to note that any kind of value may be put into value boxes, including IO actions and functions.<br />
<br />
Try doing this with a spreadsheet: <tt>fIncls := [get(ve) * get(vVat) | ve <- vExcls]</tt>. Or this: <tt>fIncl1 := apply(get(vVatFunc), get(vExcl1))</tt>.<br />
<br />
If you're wondering why I'm not using Haskell syntax, it's to focus on the meaning of boxes rather than what the functions and combinators mean. That said, this pseudo-imperative syntax is on its way out as it's getting too clunky (that <tt>apply</tt> function is really just ugly). For a quick peek ahead the last few examples would be something like this in reactive-banana:<br />
<br />
<haskell>fIncls = map (\ve -> (*) <$> ve <*> fVat) vExcls<br />
fIncl1 = fVatFunc <*> vExcl1</haskell><br />
<br />
== Events ==<br />
<br />
Let's say we want to build the worlds worst synthesizer. We have 7 buttons: &ldquo;a&rdquo;, &ldquo;b&rdquo;, &ldquo;c&rdquo;, &ldquo;d&rdquo;, &ldquo;e&rdquo;, &ldquo;f&rdquo; and &ldquo;g&rdquo;. Our output is generated by sampling a box twice per second and playing the frequency in the box until the next sample is taken.<br />
<br />
This can't be expressed with the crude formula and value boxes system we've had so far. There is no way to express key presses in that system, a key press isn't like changing a value, it's something that occurs on a specific point in time but after it occurs it's forgotten (your keyboard doesn't remember key strokes, at least mine doesn't).<br />
<br />
In this new system we'll forget about formula boxes and value boxes and introduce event boxes. Event boxes are like formula boxes in that they can refer to the value of other boxes. Event boxes can also react to events.<br />
<br />
Events can be thought of like signals in something like D-Bus. Multiple things (event boxes) can listen to them and do something once a specific event is fired (triggered).<br />
<br />
Every event has a value associated with it. Sometimes the value isn't important because the fact that the event has occurred is what's interesting but often we do want to know the value.<br />
<br />
Events come in streams. When we say event box ''b1'' changes to the value of event ''e1'' when it receives that event we're actually saying that whenever an event from the stream of events we colloquially call ''e1'' comes ''b1'' changes to the value of that event.<br />
<br />
Yes, that's confusing so I'll try to be precise. Just remember that when I refer to something like ''e1'' when defining an event box it's always to a stream of events, never a specific event.<br />
<br />
If you're puzzled by the stream just think of it as an acknowledgement that a certain kind of event can occur multiple times. It actually goes a lot deeper than that, involving those confusing <tt>[(t, e)]</tt> types, but for now just remembering that a kind of event can occur multiple times with possibly different values is good enough.<br />
<br />
Events have values and we can use that to chose to do something only for events with some value. So not only can we determine which streams of events we'll do something with when defining an event box, we can also determine for what values of events we'll do something.<br />
<br />
For example if we have an event that directly sets our synthesizer frequency we can apply a filter that only allows events with frequencies that are pleasant to the human ear.<br />
<br />
== Some reactive-banana syntax ==<br />
<br />
Expressing event handling with the pseudo-code I've used before is tricky and gets near impossible soon. So it's a good thing that once you've understood or at least got a basic idea of the concepts of event streams and event boxes the syntax of reactive-banana starts to make sense. In this section I'll explain the most fundamental functions and operators.<br />
<br />
If you're reading the [http://hackage.haskell.org/package/reactive-banana-0.5.0.0 reactive-banana 0.5 haddocks] there are a few things to keep in mind. The first is that what I've called an event box in the previous section is called a Behaviour in reactive-banana. To avoid confusion I'll stop using the term event box from here on.<br />
<br />
In the reactive-banana haddocks you'll find a lot of references to time-varying functions and lists involving time variables. Just ignore those, they're important but we'll get to them later. As a general rule just ignore what you don't understand.<br />
<br />
You'll also notice a <hask>t</hask> parameter on the <hask>Event</hask> and <hask>Behavior</hask> types. It's basically similar to the <hask>s</hask> parameter for <hask>STRef</hask>, it's a trick to use the type system to prevent constructs that would result in undefined or incorrect behavior. Just ignore it.<br />
<br />
For understanding the next sections you'll need to know about a basic subset of reactive-banana which I'll explain here. First up: event streams.<br />
<br />
=== Events ===<br />
<br />
Event streams are represented by the type Event in reactive-banana. The type <hask>Event t Int</hask> means a stream of events carrying Int values.<br />
<br />
There are three basic things you can do with just event streams. You can transform the events in them, you can filter in events in them and you can combine the event streams.<br />
<br />
Transforming an event stream means changing the values carried by the events in them. As this is ''Functional'' Reactive Programming the streams themselves are not changed. When you transform a stream you create a new stream. Whenever an event in the old stream is fired an event in the new stream is also fired, but with a different value.<br />
<br />
Transforming an event stream is done primarily by good old fmap. The expression <hask>show `fmap` eInt</hask> (or with the (<hask><$></hask>) operator <hask>show <$> eInts</hask>) with ''eInt'' having the type <hask>Event t Int</hask> creates a new event stream of the type <hask>Event String</hask> with the int in every event in the original stream being a string in the new stream.<br />
<br />
To replace the value of an event (if the event doesn't carry a useful value) just use (<hask><$</hask>): <hask>"MOO!" <$ eWhatever</hask> causes every value in the stream eWhatever to be replaced by MOO!. Like (<hask><$></hask>) this is an operator from Control.Applicative.<br />
<br />
Filtering is done using the <hask>filterE</hask> function. When you filter an event stream you create a new event stream with the same associated values but which doesn't contain all the events from the original stream. To only deal with events with positive integers you can create a filtered stream using <hask>filterE (>= 0) eInt</hask>.<br />
<br />
Combining event streams creates a new event stream with all the events from both streams. So if you combine ''eOne'' and ''eTwo'' into ''eThree'' there will be an event in ''eThree'' for every event in ''eOne'' and for every event in ''eTwo''.<br />
<br />
Combining is done with the union function: <hask>eThree = eOne `union` eTwo</hask>. Beware however that when events come in at the same time things can get a little tricky, you'd have to wonder in what order the events are processed. Reactive-banana contains several functions to handle simultaneous events. For the purpose of this page we'll do the easiest thing and ignore simultaneous events. In real world code you would need to think about it.<br />
<br />
=== Behaviors ===<br />
<br />
To create a behavior (event box) in reactive-banana you'll typically use one of two functions: <hask>stepper</hask> and <hask>accumB</hask>. Both work with an initial value and an event stream. The difference is that when an event occurs <hask>stepper</hask> changes the value of the behavior to the value in the event while <hask>accumB</hask> applies the function in the event to the value of the behavior.<br />
<br />
<haskell>eNewVal :: Event t Int<br />
bSet :: Behavior t Int<br />
bSet = stepper 0 eNewVal<br />
<br />
eUpdater :: Event t (Int -> Int)<br />
bUpdated :: Behavior t Int<br />
bUpdated = accumB 0 eUpdater</haskell><br />
The expression <hask>bSet = stepper 0 eNewVal</hask> creates a behavior named ''bSet'' with initially value 0. Once an event from the ''eNewVal'' stream comes in the value of ''bInt'' changes to the value in that event. So if an event comes in with value 2 the value of bSet becomes 2.<br />
<br />
On the other hand the expression <hask>bUpdated = accumB 0 eUpdater</hask> makes ''bUpdated'' a behavior with initially the value 0 but which gets updated (modified) whenever an event comes in. If an event comes in with value (+1) (a slice, so <hask>\x -> x + 1</hask>) and the current value of ''bUpdated'' is 1 the new value becomes 2.<br />
<br />
That's basically it for behaviors. Well, there's a third way to create behaviors: using <hask>pure</hask>. To create a behavior with the value 1 which doesn't change at all use <hask>pure 1</hask>. In case you didn't know, for applicative functors (which behaviors are) <hask>pure</hask> is what <hask>return</hask> is for monads.<br />
<br />
To create a behavior that's depends on old behaviors (<hask>f3 := get(f1) + get(f2)</hask> in our old formula box syntax) we have to use applicative functor functions in reactive-banana. There is unfortunately no option to use monad syntax. To express that the value of ''b3'' is the sum of the value of ''b1'' and the value of ''b2'' we write: <hask>b3 = (+) <$> b1 <*> b2</hask>.<br />
<br />
== Example: the worlds worst synthesizer ==<br />
<br />
Now for an example. We'd like to create a synthesizer. The synthesizer will use our keyboard for input, which we notice through a stream of events called ''eKey'' with as associated value a Char containing the key that was pressed. Something outside our program (and scope of discussion) samples the behavior ''bNote'' every 100ms and plays the tone currently in there until the next sample time.<br />
<br />
To avoid getting caught up in music theory (read: I'm lazy and can't be bothered to look up tone frequencies) the note to play is expressed as an algebraic data type.<br />
<br />
<haskell>type Octave = Int<br />
data Pitch = PA | PB | PC | PD | PE | PF | PG<br />
data Note = Note Octave Pitch<br />
<br />
-- Type signature for the key event, it comes from outside our<br />
-- system.<br />
eKey :: Event t Char</haskell><br />
You'll notice the octave. To change the octave we'll use the '-' and '+' keys. To set the pitch we'll use the 'a'..'g' keys on the keyboard. Never mind that it's really annoying to play with those keys as they're scattered all over the keyboard, this is about the FRP logic not practicality.<br />
<br />
Those chars in the ''eKey'' event stream need to be translated to pitches. Here's one way to do that.<br />
<br />
<haskell>ePitch :: Event t Pitch<br />
ePitch = (PA <$ filterE (=='a') eKey) `union`<br />
(PB <$ filterE (=='b') eKey) `union`<br />
... <br />
(PG <$ filterE (=='g') eKey)</haskell><br />
The &ldquo;trouble&rdquo; here is that we're filtering the stream multiple times, not very efficient. Here's a better way.<br />
<br />
<haskell>table = [('a', PA), ('b', PB), ..., ('g', PG)]<br />
ePitch = filterJust $ (\e -> lookup e table) <$> eKey</haskell><br />
The <hask>filterJust</hask> function is a simple helper in reactive-banana. It filters out <hask>Nothing</hask> events and returns the value inside the <hask>Just</hask> constructor for <hask>Just</hask> events. To get ''ePitch'' we first look up the characters in the translation table and then remove all events who's chars aren't in the table, removing the <hask>Just</hask> wrapper from events who's chars are in the table at the same time.<br />
<br />
The ''bNote'' behavior will not use these events directly, instead ''bOctave'' and ''bPitch'' will each store part of the note and ''bNote'' will combine the information.<br />
<br />
<haskell>eOctChange :: Char -> Maybe (Octave -> Octave)<br />
eOctChange c = case c of<br />
'+' -> Just (+1)<br />
'-' -> Just (subtract 1)<br />
_ -> Nothing<br />
<br />
bOctave :: Behavior t Octave<br />
bOctave = accumB 0 $ filterJust (eOctChange <$> eKey)<br />
<br />
bPitch :: Behavior t Pitch<br />
bPitch = stepper PC ePitch<br />
<br />
bNote :: Behavior t Note<br />
bNote = Note <$> bOctave <*> bPitch</haskell><br />
If you understand what's going on here you should have a basic idea of what FRP is in practice. There are of course considerations in the real world that we've skipped over here, such as how to get the keyboard event and how to play the sounds. To get a better idea of what FRP in the real world looks take a look at the [http://www.haskell.org/haskellwiki/Reactive-banana/Examples reactive-banana examples], they should be easy to follow.<br />
<br />
When following those examples you'll come across the (<hask><@</hask>) and (<hask><@></hask>) operators. I'll give a short introduction here to make it easier to understand the examples. The (<hask><@</hask>) operator is used like this: <hask>e2 = b1 <@ e1</hask>, if an event in stream ''e1'' comes in the value of that event is replaced in the ''e2'' stream by whatever value is in ''b1'' at the time. The (<hask><@></hask>) operator is used in much the same way, but it doesn't replace the value from ''e1'' outright but uses it to compute a new value.<br />
<br />
<haskell>bOne :: Behavior t Int<br />
bOne = pure 1<br />
<br />
bPlusOne :: Behavior t (Int -> Int)<br />
bPlusOne = pure (+1)<br />
<br />
eAlwaysOne, ePlusOne :: Event t Int<br />
eAlwaysOne = bOne <@ eWhatever<br />
ePlusOne = bPlusOne <@> eInt</haskell><br />
<br />
== Time-varying values and functions ==<br />
<br />
If you've read about FRP before you're likely to have come across the term &ldquo;time-varying function&rdquo;. This sounds difficult, but once you understand the basics of behaviors and events it's really no big deal.<br />
<br />
Here's the clue: a behavior contains a value, but the value can change. Therefore at different points in time a behavior can have different values. So we could say that a behavior has a value that varies in time.<br />
<br />
We could also throw away the concept of boxes and say a behavior ''is'' a value that varies in time. This is more correct, those boxes are helpful as teaching concepts but once we talk directly about time they are no longer needed.<br />
<br />
So, a time-varying value is simply a behavior as behaviors can have different values at different points in time. A time-varying function is also just a behavior, one where the value is a function (functional programming 101: the clue to every riddle is that functions are values).<br />
<br />
To go further down the rabbit hole a time-varying value can actually be thought of as a function by making time explicit. If a behavior has value 1 up to the 30th's second and from that point forward value 2 we could express the behavior as: <hask>\t -> if t < 30 then 1 else 2</hask>. This is important: by making time explicit we can reason about behaviors as if they were pure functions. While in practice we're dealing with applicative functors (or in other libraries monads or arrows) we can think of behaviors as pure functions.<br />
<br />
Real world behaviors aren't as simple as from 30 seconds onwards change to value 2. They interact with events. So to express such behaviors as pure functions events need to be expressed in a way that works for pure functions. This is where the <hask>[(t,e)]</hask> type comes in. We can see events as a list of values at certain points in time, for example <hask>[(10, 1), (20, 2), (30, 3)]</hask> for events that occur on second 10, 20 and 30 with values 1, 2 and 3 respectively.<br />
<br />
When viewing events in such a way it becomes easy to create a behavior that changes to whatever value was last:<br />
<br />
<haskell>type Time = Int<br />
stepped :: [(Time, Int)] -> Time -> Int<br />
stepped es t = case takeWhile (\(t', _) -> t' < t) es of <br />
[] -> 0 <br />
xs -> snd (last xs)</haskell><br />
For once this is actually runnable code. If we invoke it as <hask>stepped [(10,1),(20,1),(30,1)] 2</hask> the result is 0, if we invoke it as <hask>stepped [(10,1),(20,1),(30,1)] 12</hask> the result is 1, as expected.<br />
<br />
Stepped sounds a lot like stepper and we can create that function by making a few small adjustments.<br />
<br />
<haskell>type Time = Int<br />
stepper :: a -> [(Time, a)] -> (Time -> a)<br />
stepper d es = \t -> case takeWhile (\(t', _) -> t' < t) es of<br />
[] -> d<br />
xs -> snd (last xs)</haskell><br />
If you understand this bit, why behaviors and events can be expressed by making time explicit you have a good intuition of what FRP is.<br />
<br />
== Making the example runnable ==<br />
<br />
After I wrote this page I got questions about how to actually run the reactive-banana examples. Here's a big block of code that can be pasted into a file and run:<br />
<br />
<haskell>module Main where<br />
<br />
import Data.Char (toUpper)<br />
import Control.Monad (forever)<br />
import System.IO (BufferMode(..), hSetEcho, hSetBuffering, stdin)<br />
import Reactive.Banana<br />
import Reactive.Banana.Frameworks.AddHandler<br />
import Reactive.Banana.Frameworks<br />
<br />
type Octave = Int<br />
<br />
data Pitch = PA | PB | PC | PD | PE | PF | PG<br />
deriving (Eq, Enum)<br />
<br />
-- Mapping between pitch and the char responsible for it.<br />
pitchChars :: [(Pitch, Char)]<br />
pitchChars = [(p, toEnum $ fromEnum 'a' + fromEnum p) |<br />
p <- [PA .. PG]]<br />
<br />
-- Reverse of pitchChars<br />
charPitches :: [(Char, Pitch)]<br />
charPitches = [(b, a) | (a, b) <- pitchChars]<br />
<br />
data Note = Note Octave Pitch<br />
<br />
instance Show Pitch where<br />
show p = case lookup p pitchChars of<br />
Nothing -> error "cannot happen"<br />
Just c -> [toUpper c]<br />
<br />
instance Show Note where<br />
show (Note o p) = show p ++ show o<br />
<br />
-- Filter and transform events at the same time.<br />
filterMapJust :: (a -> Maybe b) -> Event t a -> Event t b<br />
filterMapJust f = filterJust . fmap f<br />
<br />
-- Change the original octave by adding a number of octaves, taking<br />
-- care to limit the resulting octave to the 0..10 range.<br />
changeOctave :: Int -> Octave -> Octave<br />
changeOctave d = max 0 . min 10 . (d+)<br />
<br />
-- Get the octave change for the '+' and '-' chars.<br />
getOctaveChange :: Char -> Maybe Int<br />
getOctaveChange c = case c of<br />
'+' -> Just 1<br />
'-' -> Just (-1)<br />
_ -> Nothing<br />
<br />
makeNetworkDescription :: Frameworks t<br />
=> AddHandler Char<br />
-> Moment t ()<br />
makeNetworkDescription addKeyEvent = do<br />
eKey <- fromAddHandler addKeyEvent<br />
let<br />
eOctaveChange = filterMapJust getOctaveChange eKey<br />
bOctave = accumB 3 (changeOctave <$> eOctaveChange)<br />
ePitch = filterMapJust (`lookup` charPitches) eKey<br />
bPitch = stepper PC ePitch<br />
bNote = Note <$> bOctave <*> bPitch<br />
eNoteChanged <- changes bNote<br />
reactimate' $ fmap (\n -> putStrLn ("Now playing " ++ show n))<br />
<$> eNoteChanged<br />
<br />
main :: IO ()<br />
main = do<br />
(addKeyEvent, fireKey) <- newAddHandler<br />
network <- compile (makeNetworkDescription addKeyEvent)<br />
actuate network<br />
hSetEcho stdin False<br />
hSetBuffering stdin NoBuffering<br />
forever (getChar >>= fireKey)</haskell><br />
If you compare this to the previous example you'll notice some changes in the events and behaviors. This version is more real-world, there are bounds checks and some abstraction (<hask>filterMapJust</hask>).<br />
<br />
The parts answering the question &ldquo;how to run it?&rdquo; are all in <hask>makeNetworkDescription</hask> and <hask>main</hask>. In reactive-banana you first create a description of an event network, then compile that network, enable it and call your normal Haskell event loop. At least, that's the case when you don't use a GUI framework with reactive-banana integration, if you use the wx integration for reactive-banana the event loop is already written for you and some other details are different. See the [http://www.haskell.org/haskellwiki/Reactive-banana/Examples examples].<br />
<br />
All the events and behaviors live in what reactive-banana calls an event network. It's not possible to use behaviors outside this network, you can't for example see inside a behavior from IO code. You can use events though and that's how you couple the FRP stuff inside the event network to the outside world.<br />
<br />
To create an event that you can fire from outside the event network use <hask>newAddHandler</hask> in the IO monad. It gives you two things, an <hask>AddHandler</hask> value and an IO action that takes a value and fires an event with that value. By passing the <hask>AddHandler</hask> value to <hask>fromAddHandler</hask> (inside the <hask>NetworkDescription</hask> monad) you'll get an event stream which you can use in a normal fashion.<br />
<br />
To handle output events use <hask>reactimate</hask>, pass it an event stream containing IO actions and whenever an event from that stream occurs the action is executed. You'll pretty much always want to use <hask>reactimate</hask> with (<hask><$></hask>)/<hask>fmap</hask> to generate those IO actions.<br />
<br />
Once the network description is complete you can compile it. This gives you back an <hask>EventNetwork</hask> value. You can start the <hask>EventNetwork</hask> with <hask>actuate</hask>. This sets things up so that events can actually be received.<br />
<br />
In our roll-your-own program we'll use <hask>getChar</hask> (after turning off echo and buffering on the standard input stream) to receive characters. When a character is received the ''bNote'' is updated and a message is printed with the new value (actually playing a tone appears to involve more code than I'd like to include here).<br />
<br />
Wait? Didn't I say we can't actually observe the value of a behavior? So how do we know which note to play? Turns out reactive-banana has a nice little function called <hask>changes</hask>. When used on a behavior it returns an event stream which contains the new values whenever the behavior is updated. This event stream is passed to <hask>reactimate</hask> to trigger the prints.<br />
<br />
== A broader view of FRP ==<br />
<br />
FRP is a field which is currently in active development, many different approach are being tried and no real standard has been found yet. The [http://hackage.haskell.org/packages/archive/pkg-list.html#cat:frp FRP category on hackage] has a lot of different packages with varying approaches to implementing FRP. Some focus on applicative functors, some on monads and others on arrows.<br />
<br />
Semantics can be subtly or not-so-sublty different between FRP libraries and sometimes naming is different as well (for example signal instead of event).<br />
<br />
In this page I've tried to explain FRP using one specific library (reactive-banana). While this makes things simpler for getting an idea of FRP it can give some wrong impressions due to conflating the limitations of reactive-banana and that of FRP in general.<br />
<br />
[[Category:FRP]] [[Category:Tutorials]]</div>Fa-mlhttps://wiki.haskell.org/index.php?title=FRP_explanation_using_reactive-banana&diff=61323FRP explanation using reactive-banana2016-12-16T17:53:58Z<p>Fa-ml: /* Reactive programming for the masses: the spreadsheet */ formula error</p>
<hr />
<div>This is an attempt to explain Functional Reactive Programming (FRP) enough to give a reader with no previous exposure to FRP an intuition what FRP is about. After reading this you should hopefully understand enough of FRP to understand the [http://www.haskell.org/haskellwiki/Reactive-banana reactive-banana] examples.<br />
<br />
FRP has certain terms such as behavior, event and time-varying that can be confusing for people unfamiliar with it. I'll avoid these terms at first and will focus on spreadsheets and a generalization of spreadsheet cells (which I will call boxes). Later, once the most important concepts are explained, reactive-banana syntax will be introduced along with an example that demonstrates how to work with behaviors and events in reactive-banana. Finally some theory about time-varying functions and how events and behaviors can be implemented using pure functions by making time explicit should provide the necessary background to understand reactive-banana's haddock comments.<br />
<br />
The version of reactive-banana used here is [http://hackage.haskell.org/package/reactive-banana-0.8.0.0 0.8.0.0].<br />
<br />
== Reactive programming for the masses: the spreadsheet ==<br />
<br />
Spreadsheets are something we all (for certain values of we) know about. Let's talk about a typical, simplified, spreadsheet. We have a list of products that we sell and want to compute their price with the Value Added Tax (VAT) added. We might have cells A1 to A10 contain the raw prices of our products and cell B1 contain the current VAT rate (say 19 for a 19% VAT). In cells C1 to C10 we'd like to see the prices including VAT.<br />
<br />
In cell C1 we'd have a formula: <tt>=A1*(100+B1/100)</tt>, in cell C2 <tt>=A2*(100+B1/100)</tt>, etc. So if A1 contains $100 C1 would contain $119.<br />
<br />
But what if the government, in its eternal quest to reduce the budget deficit, raises the VAT rate? We'd adjust cell B1, just change it to 20. And like magic all the C cells are updated.<br />
<br />
Though this may seem mundane what we've just seen is actually a very good example of reactive programming. We didn't tell the C cells to update; they updated on their own because a value they depend on changed.<br />
<br />
== From cells to boxes: generalizing the spreadsheet ==<br />
<br />
Spreadsheets are nice, but if we want to truly get a feel for FRP we'll have to think beyond them. If we look at a spreadsheet at an abstract level it pretty much consists of cells of two types: value cells (<tt>19</tt>) and formula cells (<tt>=A1*(100+B1/100)</tt>). Let's lose the reference to spreadsheets and talk about boxes.<br />
<br />
Say, for now, that there are two kinds of boxes: formula boxes and value boxes. Both support a &ldquo;get&rdquo; operation that returns a value. Value boxes additionally support a &ldquo;set&rdquo; operation that sets the value.<br />
<br />
Formula boxes can contain any kind of pure function. They can also refer to the values of other boxes (both formula and value boxes). Value boxes don't have a function inside them, they have a value.<br />
<br />
The translation of our VAT spreadsheet would be something like a formula box ''fIncl1'' containing the expression <tt>get(vExcl1) * (1 + get(vVat) / 100)</tt>. This expression uses two value boxes: ''vExcl1'' and ''vVat''.<br />
<br />
We could also write ''fIncl1'' using a helper formula box ''fVat''. Let ''fVat'' have the formula <tt>1 + get(vVat) / 100</tt> and ''fIncl1'' have the formula <tt>get(vExcl1) * get(vVat)</tt>. I'll use <tt>:=</tt> for this kind of definition, the <tt>:=</tt> is there to remind you that this isn't Haskell.<br />
<br />
It's important to note that any kind of value may be put into value boxes, including IO actions and functions.<br />
<br />
Try doing this with a spreadsheet: <tt>fIncls := [get(ve) * get(vVat) | ve <- vExcls]</tt>. Or this: <tt>fIncl1 := apply(get(vVatFunc), get(vExcl1))</tt>.<br />
<br />
If you're wondering why I'm not using Haskell syntax, it's to focus on the meaning of boxes rather than what the functions and combinators mean. That said, this pseudo-imperative syntax is on its way out as it's getting too clunky (that <tt>apply</tt> function is really just ugly). For a quick peek ahead the last few examples would be something like this in reactive-banana:<br />
<br />
<haskell>fIncls = map (\ve -> (*) <$> ve <*> fVat) vExcls<br />
fIncl1 = fVatFunc <*> vExcl1</haskell><br />
<br />
== Events ==<br />
<br />
Let's say we want to build the worlds worst synthesizer. We have 7 buttons: &ldquo;a&rdquo;, &ldquo;b&rdquo;, &ldquo;c&rdquo;, &ldquo;d&rdquo;, &ldquo;e&rdquo;, &ldquo;f&rdquo; and &ldquo;g&rdquo;. Our output is generated by sampling a box twice per second and playing the frequency in the box until the next sample is taken.<br />
<br />
This can't be expressed with the crude formula and value boxes system we've had so far. There is no way to express key presses in that system, a key press isn't like changing a value, it's something that occurs on a specific point in time but after it occurs it's forgotten (your keyboard doesn't remember key strokes, at least mine doesn't).<br />
<br />
In this new system we'll forget about formula boxes and value boxes and introduce event boxes. Event boxes are like formula boxes in that they can refer to the value of other boxes. Event boxes can also react to events.<br />
<br />
Events can be thought of like signals in something like D-Bus. Multiple things (event boxes) can listen to them and do something once a specific event is fired (triggered).<br />
<br />
Every event has a value associated with it. Sometimes the value isn't important because the fact that the event has occurred is what's interesting but often we do want to know the value.<br />
<br />
Events come in streams. When we say event box ''b1'' changes to the value of event ''e1'' when it receives that event we're actually saying that whenever an event from the stream of events we colloquially call ''e1'' comes ''b1'' changes to the value of that event.<br />
<br />
Yes, that's confusing so I'll try to be precise. Just remember that when I refer to something like ''e1'' when defining an event box it's always to a stream of events, never a specific event.<br />
<br />
If you're puzzled by the stream just think of it as an acknowledgement that a certain kind of event can occur multiple times. It actually goes a lot deeper than that, involving those confusing <tt>[(t, e)]</tt> types, but for now just remembering that a kind of event can occur multiple times with possibly different values is good enough.<br />
<br />
Events have values and we can use that to chose to do something only for events with some value. So not only can we determine which streams of events we'll do something with when defining an event box, we can also determine for what values of events we'll do something.<br />
<br />
For example if we have an event that directly sets our synthesizer frequency we can apply a filter that only allows events with frequencies that are pleasant to the human ear.<br />
<br />
== Some reactive-banana syntax ==<br />
<br />
Expressing event handling with the pseudo-code I've used before is tricky and gets near impossible soon. So it's a good thing that once you've understood or at least got a basic idea of the concepts of event streams and event boxes the syntax of reactive-banana starts to make sense. In this section I'll explain the most fundamental functions and operators.<br />
<br />
If you're reading the [http://hackage.haskell.org/package/reactive-banana-0.5.0.0 reactive-banana 0.5 haddocks] there are a few things to keep in mind. The first is that what I've called an event box in the previous section is called a Behaviour in reactive-banana. To avoid confusion I'll stop using the term event box from here on.<br />
<br />
In the reactive-banana haddocks you'll find a lot of references to time-varying functions and lists involving time variables. Just ignore those, they're important but we'll get to them later. As a general rule just ignore what you don't understand.<br />
<br />
You'll also notice a <hask>t</hask> parameter on the <hask>Event</hask> and <hask>Behavior</hask> types. It's basically similar to the <hask>s</hask> parameter for <hask>STRef</hask>, it's a trick to use the type system to prevent constructs that would result in undefined or incorrect behavior. Just ignore it.<br />
<br />
For understanding the next sections you'll need to know about a basic subset of reactive-banana which I'll explain here. First up: event streams.<br />
<br />
=== Events ===<br />
<br />
Event streams are represented by the type Event in reactive-banana. The type <hask>Event t Int</hask> means a stream of events carrying Int values.<br />
<br />
There are three basic things you can do with just event streams. You can transform the events in them, you can filter in events in them and you can combine the event streams.<br />
<br />
Transforming an event stream means changing the values carried by the events in them. As this is ''Functional'' Reactive Programming the streams themselves are not changed. When you transform a stream you create a new stream. Whenever an event in the old stream is fired an event in the new stream is also fired, but with a different value.<br />
<br />
Transforming an event stream is done primarily by good old fmap. The expression <hask>show `fmap` eInt</hask> (or with the (<hask><$></hask>) operator <hask>show <$> eInts</hask>) with ''eInt'' having the type <hask>Event t Int</hask> creates a new event stream of the type <hask>Event String</hask> with the int in every event in the original stream being a string in the new stream.<br />
<br />
To replace the value of an event (if the event doesn't carry a useful value) just use (<hask><$</hask>): <hask>"MOO!" <$ eWhatever</hask> causes every value in the stream eWhatever to be replaced by MOO!. Like (<hask><$></hask>) this is an operator from Control.Applicative.<br />
<br />
Filtering is done using the <hask>filterE</hask> function. When you filter an event stream you create a new event stream with the same associated values but which doesn't contain all the events from the original stream. To only deal with events with positive integers you can create a filtered stream using <hask>filterE (>= 0) eInt</hask>.<br />
<br />
Combining event streams creates a new event stream with all the events from both streams. So if you combine ''eOne'' and ''eTwo'' into ''eThree'' there will be an event in ''eThree'' for every event in ''eOne'' and for every event in ''eTwo''.<br />
<br />
Combining is done with the union function: <hask>eThree = eOne `union` eTwo</hask>. Beware however that when events come in at the same time things can get a little tricky, you'd have to wonder in what order the events are processed. Reactive-banana contains several functions to handle simultaneous events. For the purpose of this page we'll do the easiest thing and ignore simultaneous events. In real world code you would need to think about it.<br />
<br />
=== Behaviors ===<br />
<br />
To create a behavior (event box) in reactive-banana you'll typically use one of two functions: <hask>stepper</hask> and <hask>accumB</hask>. Both work with an initial value and an event stream. The difference is that when an event occurs <hask>stepper</hask> changes the value of the behavior to the value in the event while <hask>accumB</hask> applies the function in the event to the value of the behavior.<br />
<br />
<haskell>eNewVal :: Event t Int<br />
bSet :: Behavior t Int<br />
bSet = stepper 0 eNewVal<br />
<br />
eUpdater :: Event t (Int -> Int)<br />
bUpdated :: Behavior t Int<br />
bUpdated = accumB 0 eUpdater</haskell><br />
The expression <hask>bSet = stepper 0 eNewVal</hask> creates a behavior named ''bSet'' with initially value 0. Once an event from the ''eNewVal'' stream comes in the value of ''bInt'' changes to the value in that event. So if an event comes in with value 2 the value of bSet becomes 2.<br />
<br />
On the other hand the expression <hask>bUpdated = accumB 0 eUpdater</hask> makes ''bUpdated'' a behavior with initially the value 0 but which gets updated (modified) whenever an event comes in. If an event comes in with value (+1) (a slice, so <hask>\x -> x + 1</hask>) and the current value of ''bUpdated'' is 1 the new value becomes 2.<br />
<br />
That's basically it for behaviors. Well, there's a third way to create behaviors: using <hask>pure</hask>. To create a behavior with the value 1 which doesn't change at all use <hask>pure 1</hask>. In case you didn't know, for applicative functors (which behaviors are) <hask>pure</hask> is what <hask>return</hask> is for monads.<br />
<br />
To create a behavior that's depends on old behaviors (<hask>f3 := get(f1) + get(f2)</hask> in our old formula box syntax) we have to use applicative functor functions in reactive-banana. There is unfortunately no option to use monad syntax. To express that the value of ''b3'' is the sum of the value of ''b1'' and the value of ''b2'' we write: <hask>b3 = (+) <$> b1 <*> b2</hask>.<br />
<br />
== Example: the worlds worst synthesizer ==<br />
<br />
Now for an example. We'd like to create a synthesizer. The synthesizer will use our keyboard for input, which we notice through a stream of events called ''eKey'' with as associated value a Char containing the key that was pressed. Something outside our program (and scope of discussion) samples the behavior ''bNote'' every 100ms and plays the tone currently in there until the next sample time.<br />
<br />
To avoid getting caught up in music theory (read: I'm lazy and can't be bothered to look up tone frequencies) the note to play is expressed as an algebraic data type.<br />
<br />
<haskell>type Octave = Int<br />
data Pitch = PA | PB | PC | PD | PE | PF | PG<br />
data Note = Note Octave Pitch<br />
<br />
-- Type signature for the key event, it comes from outside our<br />
-- system.<br />
eKey :: Event t Char</haskell><br />
You'll notice the octave. To change the octave we'll use the '-' and '+' keys. To set the pitch we'll use the 'a'..'g' keys on the keyboard. Never mind that it's really annoying to play with those keys as they're scattered all over the keyboard, this is about the FRP logic not practicality.<br />
<br />
Those chars in the ''eKey'' event stream need to be translated to pitches. Here's one way to do that.<br />
<br />
<haskell>ePitch :: Event t Pitch<br />
ePitch = (PA <$ filterE (=='a') eKey) `union`<br />
(PB <$ filterE (=='b') eKey) `union`<br />
... <br />
(PG <$ filterE (=='g') eKey)</haskell><br />
The &ldquo;trouble&rdquo; here is that we're filtering the stream multiple times, not very efficient. Here's a better way.<br />
<br />
<haskell>table = [('a', PA), ('b', PB), ..., ('g', PG)]<br />
ePitch = filterJust $ (\e -> lookup e table) <$> eKey</haskell><br />
The <hask>filterJust</hask> function is a simple helper in reactive-banana. It filters out <hask>Nothing</hask> events and returns the value inside the <hask>Just</hask> constructor for <hask>Just</hask> events. To get ''ePitch'' we first look up the characters in the translation table and then remove all events who's chars aren't in the table, removing the <hask>Just</hask> wrapper from events who's chars are in the table at the same time.<br />
<br />
The ''bNote'' behavior will not use these events directly, instead ''bOctave'' and ''bPitch'' will each store part of the note and ''bNote'' will combine the information.<br />
<br />
<haskell>eOctChange :: Char -> Maybe (Octave -> Octave)<br />
eOctChange c = case c of<br />
'+' -> Just (+1)<br />
'-' -> Just (subtract 1)<br />
_ -> Nothing<br />
<br />
bOctave :: Behavior t Octave<br />
bOctave = accumB 0 $ filterJust (eOctChange <$> eKey)<br />
<br />
bPitch :: Behavior t Pitch<br />
bPitch = stepper PC ePitch<br />
<br />
bNote :: Behavior t Note<br />
bNote = Note <$> bOctave <*> bPitch</haskell><br />
If you understand what's going on here you should have a basic idea of what FRP is in practice. There are of course considerations in the real world that we've skipped over here, such as how to get the keyboard event and how to play the sounds. To get a better idea of what FRP in the real world looks take a look at the [http://www.haskell.org/haskellwiki/Reactive-banana/Examples reactive-banana examples], they should be easy to follow.<br />
<br />
When following those examples you'll come across the (<hask><@</hask>) and (<hask><@></hask>) operators. I'll give a short introduction here to make it easier to understand the examples. The (<hask><@</hask>) operator is used like this: <hask>e2 = b1 <@ e1</hask>, if an event in stream ''e1'' comes in the value of that event is replaced in the ''e2'' stream by whatever value is in ''b1'' at the time. The (<hask><@></hask>) operator is used in much the same way, but it doesn't replace the value from ''e1'' outright but uses it to compute a new value.<br />
<br />
<haskell>bOne :: Behavior t Int<br />
bOne = pure 1<br />
<br />
bPlusOne :: Behavior t (Int -> Int)<br />
bPlusOne = pure (+1)<br />
<br />
eAlwaysOne, ePlusOne :: Event t Int<br />
eAlwaysOne = bOne <@ eWhatever<br />
ePlusOne = bPlusOne <@> eInt</haskell><br />
<br />
== Time-varying values and functions ==<br />
<br />
If you've read about FRP before you're likely to have come across the term &ldquo;time-varying function&rdquo;. This sounds difficult, but once you understand the basics of behaviors and events it's really no big deal.<br />
<br />
Here's the clue: a behavior contains a value, but the value can change. Therefore at different points in time a behavior can have different values. So we could say that a behavior has a value that varies in time.<br />
<br />
We could also throw away the concept of boxes and say a behavior ''is'' a value that varies in time. This is more correct, those boxes are helpful as teaching concepts but once we talk directly about time they are no longer needed.<br />
<br />
So, a time-varying value is simply a behavior as behaviors can have different values at different points in time. A time-varying function is also just a behavior, one where the value is a function (functional programming 101: the clue to every riddle is that functions are values).<br />
<br />
To go further down the rabbit hole a time-varying value can actually be thought of as a function by making time explicit. If a behavior has value 1 up to the 30th's second and from that point forward value 2 we could express the behavior as: <hask>\t -> if t < 30 then 1 else 2</hask>. This is important: by making time explicit we can reason about behaviors as if they were pure functions. While in practice we're dealing with applicative functors (or in other libraries monads or arrows) we can think of behaviors as pure functions.<br />
<br />
Real world behaviors aren't as simple as from 30 seconds onwards change to value 2. They interact with events. So to express such behaviors as pure functions events need to be expressed in a way that works for pure functions. This is where the <hask>[(t,e)]</hask> type comes in. We can see events as a list of values at certain points in time, for example <hask>[(10, 1), (20, 2), (30, 3)]</hask> for events that occur on second 10, 20 and 30 with values 1, 2 and 3 respectively.<br />
<br />
When viewing events in such a way it becomes easy to create a behavior that changes to whatever value was last:<br />
<br />
<haskell>type Time = Int<br />
stepped :: [(Time, Int)] -> Time -> Int<br />
stepped es t = case takeWhile (\(t', _) -> t' < t) es of <br />
[] -> 0 <br />
xs -> snd (last xs)</haskell><br />
For once this is actually runnable code. If we invoke it as <hask>stepped [(10,1),(20,1),(30,1)] 2</hask> the result is 0, if we invoke it as <hask>stepped [(10,1),(20,1),(30,1)] 12</hask> the result is 1, as expected.<br />
<br />
Stepped sounds a lot like stepper and we can create that function by making a few small adjustments.<br />
<br />
<haskell>type Time = Int<br />
stepper :: a -> [(Time, a)] -> (Time -> a)<br />
stepper d es = \t -> case takeWhile (\(t', _) -> t' < t) es of<br />
[] -> d<br />
xs -> snd (last xs)</haskell><br />
If you understand this bit, why behaviors and events can be expressed by making time explicit you have a good intuition of what FRP is.<br />
<br />
== Making the example runnable ==<br />
<br />
After I wrote this page I got questions about how to actually run the reactive-banana examples. Here's a big block of code that can be pasted into a file and run:<br />
<br />
<haskell>module Main where<br />
<br />
import Data.Char (toUpper)<br />
import Control.Monad (forever)<br />
import System.IO (BufferMode(..), hSetEcho, hSetBuffering, stdin)<br />
import Reactive.Banana<br />
import Reactive.Banana.Frameworks.AddHandler<br />
import Reactive.Banana.Frameworks<br />
<br />
type Octave = Int<br />
<br />
data Pitch = PA | PB | PC | PD | PE | PF | PG<br />
deriving (Eq, Enum)<br />
<br />
-- Mapping between pitch and the char responsible for it.<br />
pitchChars :: [(Pitch, Char)]<br />
pitchChars = [(p, toEnum $ fromEnum 'a' + fromEnum p) |<br />
p <- [PA .. PG]]<br />
<br />
-- Reverse of pitchChars<br />
charPitches :: [(Char, Pitch)]<br />
charPitches = [(b, a) | (a, b) <- pitchChars]<br />
<br />
data Note = Note Octave Pitch<br />
<br />
instance Show Pitch where<br />
show p = case lookup p pitchChars of<br />
Nothing -> error "cannot happen"<br />
Just c -> [toUpper c]<br />
<br />
instance Show Note where<br />
show (Note o p) = show p ++ show o<br />
<br />
-- Filter and transform events at the same time.<br />
filterMapJust :: (a -> Maybe b) -> Event t a -> Event t b<br />
filterMapJust f = filterJust . fmap f<br />
<br />
-- Change the original octave by adding a number of octaves, taking<br />
-- care to limit the resulting octave to the 0..10 range.<br />
changeOctave :: Int -> Octave -> Octave<br />
changeOctave d = max 0 . min 10 . (d+)<br />
<br />
-- Get the octave change for the '+' and '-' chars.<br />
getOctaveChange :: Char -> Maybe Int<br />
getOctaveChange c = case c of<br />
'+' -> Just 1<br />
'-' -> Just (-1)<br />
_ -> Nothing<br />
<br />
makeNetworkDescription :: Frameworks t<br />
=> AddHandler Char<br />
-> Moment t ()<br />
makeNetworkDescription addKeyEvent = do<br />
eKey <- fromAddHandler addKeyEvent<br />
let<br />
eOctaveChange = filterMapJust getOctaveChange eKey<br />
bOctave = accumB 3 (changeOctave <$> eOctaveChange)<br />
ePitch = filterMapJust (`lookup` charPitches) eKey<br />
bPitch = stepper PC ePitch<br />
bNote = Note <$> bOctave <*> bPitch<br />
eNoteChanged <- changes bNote<br />
reactimate' $ fmap (\n -> putStrLn ("Now playing " ++ show n))<br />
<$> eNoteChanged<br />
<br />
main :: IO ()<br />
main = do<br />
(addKeyEvent, fireKey) <- newAddHandler<br />
network <- compile (makeNetworkDescription addKeyEvent)<br />
actuate network<br />
hSetEcho stdin False<br />
hSetBuffering stdin NoBuffering<br />
forever (getChar >>= fireKey)</haskell><br />
If you compare this to the previous example you'll notice some changes in the events and behaviors. This version is more real-world, there are bounds checks and some abstraction (<hask>filterMapJust</hask>).<br />
<br />
The parts answering the question &ldquo;how to run it?&rdquo; are all in <hask>makeNetworkDescription</hask> and <hask>main</hask>. In reactive-banana you first create a description of an event network, then compile that network, enable it and call your normal Haskell event loop. At least, that's the case when you don't use a GUI framework with reactive-banana integration, if you use the wx integration for reactive-banana the event loop is already written for you and some other details are different. See the [http://www.haskell.org/haskellwiki/Reactive-banana/Examples examples].<br />
<br />
All the events and behaviors live in what reactive-banana calls an event network. It's not possible to use behaviors outside this network, you can't for example see inside a behavior from IO code. You can use events though and that's how you couple the FRP stuff inside the event network to the outside world.<br />
<br />
To create an event that you can fire from outside the event network use <hask>newAddHandler</hask> in the IO monad. It gives you two things, an <hask>AddHandler</hask> value and an IO action that takes a value and fires an event with that value. By passing the <hask>AddHandler</hask> value to <hask>fromAddHandler</hask> (inside the <hask>NetworkDescription</hask> monad) you'll get an event stream which you can use in a normal fashion.<br />
<br />
To handle output events use <hask>reactimate</hask>, pass it an event stream containing IO actions and whenever an event from that stream occurs the action is executed. You'll pretty much always want to use <hask>reactimate</hask> with (<hask><$></hask>)/<hask>fmap</hask> to generate those IO actions.<br />
<br />
Once the network description is complete you can compile it. This gives you back an <hask>EventNetwork</hask> value. You can start the <hask>EventNetwork</hask> with <hask>actuate</hask>. This sets things up so that events can actually be received.<br />
<br />
In our roll-your-own program we'll use <hask>getChar</hask> (after turning off echo and buffering on the standard input stream) to receive characters. When a character is received the ''bNote'' is updated and a message is printed with the new value (actually playing a tone appears to involve more code than I'd like to include here).<br />
<br />
Wait? Didn't I say we can't actually observe the value of a behavior? So how do we know which note to play? Turns out reactive-banana has a nice little function called <hask>changes</hask>. When used on a behavior it returns an event stream which contains the new values whenever the behavior is updated. This event stream is passed to <hask>reactimate</hask> to trigger the prints.<br />
<br />
== A broader view of FRP ==<br />
<br />
FRP is a field which is currently in active development, many different approach are being tried and no real standard has been found yet. The [http://hackage.haskell.org/packages/archive/pkg-list.html#cat:frp FRP category on hackage] has a lot of different packages with varying approaches to implementing FRP. Some focus on applicative functors, some on monads and others on arrows.<br />
<br />
Semantics can be subtly or not-so-sublty different between FRP libraries and sometimes naming is different as well (for example signal instead of event).<br />
<br />
In this page I've tried to explain FRP using one specific library (reactive-banana). While this makes things simpler for getting an idea of FRP it can give some wrong impressions due to conflating the limitations of reactive-banana and that of FRP in general.<br />
<br />
[[Category:FRP]] [[Category:Tutorials]]</div>Fa-mlhttps://wiki.haskell.org/index.php?title=FRP_explanation_using_reactive-banana&diff=61322FRP explanation using reactive-banana2016-12-16T17:53:32Z<p>Fa-ml: /* From cells to boxes: generalizing the spreadsheet */ formula error</p>
<hr />
<div>This is an attempt to explain Functional Reactive Programming (FRP) enough to give a reader with no previous exposure to FRP an intuition what FRP is about. After reading this you should hopefully understand enough of FRP to understand the [http://www.haskell.org/haskellwiki/Reactive-banana reactive-banana] examples.<br />
<br />
FRP has certain terms such as behavior, event and time-varying that can be confusing for people unfamiliar with it. I'll avoid these terms at first and will focus on spreadsheets and a generalization of spreadsheet cells (which I will call boxes). Later, once the most important concepts are explained, reactive-banana syntax will be introduced along with an example that demonstrates how to work with behaviors and events in reactive-banana. Finally some theory about time-varying functions and how events and behaviors can be implemented using pure functions by making time explicit should provide the necessary background to understand reactive-banana's haddock comments.<br />
<br />
The version of reactive-banana used here is [http://hackage.haskell.org/package/reactive-banana-0.8.0.0 0.8.0.0].<br />
<br />
== Reactive programming for the masses: the spreadsheet ==<br />
<br />
Spreadsheets are something we all (for certain values of we) know about. Let's talk about a typical, simplified, spreadsheet. We have a list of products that we sell and want to compute their price with the Value Added Tax (VAT) added. We might have cells A1 to A10 contain the raw prices of our products and cell B1 contain the current VAT rate (say 19 for a 19% VAT). In cells C1 to C10 we'd like to see the prices including VAT.<br />
<br />
In cell C1 we'd have a formula: <tt>=A1*(1+B1/100)</tt>, in cell C2 <tt>=A2*(1+B1/100)</tt>, etc. So if A1 contains $100 C1 would contain $119.<br />
<br />
But what if the government, in its eternal quest to reduce the budget deficit, raises the VAT rate? We'd adjust cell B1, just change it to 20. And like magic all the C cells are updated.<br />
<br />
Though this may seem mundane what we've just seen is actually a very good example of reactive programming. We didn't tell the C cells to update; they updated on their own because a value they depend on changed.<br />
<br />
== From cells to boxes: generalizing the spreadsheet ==<br />
<br />
Spreadsheets are nice, but if we want to truly get a feel for FRP we'll have to think beyond them. If we look at a spreadsheet at an abstract level it pretty much consists of cells of two types: value cells (<tt>19</tt>) and formula cells (<tt>=A1*(100+B1/100)</tt>). Let's lose the reference to spreadsheets and talk about boxes.<br />
<br />
Say, for now, that there are two kinds of boxes: formula boxes and value boxes. Both support a &ldquo;get&rdquo; operation that returns a value. Value boxes additionally support a &ldquo;set&rdquo; operation that sets the value.<br />
<br />
Formula boxes can contain any kind of pure function. They can also refer to the values of other boxes (both formula and value boxes). Value boxes don't have a function inside them, they have a value.<br />
<br />
The translation of our VAT spreadsheet would be something like a formula box ''fIncl1'' containing the expression <tt>get(vExcl1) * (1 + get(vVat) / 100)</tt>. This expression uses two value boxes: ''vExcl1'' and ''vVat''.<br />
<br />
We could also write ''fIncl1'' using a helper formula box ''fVat''. Let ''fVat'' have the formula <tt>1 + get(vVat) / 100</tt> and ''fIncl1'' have the formula <tt>get(vExcl1) * get(vVat)</tt>. I'll use <tt>:=</tt> for this kind of definition, the <tt>:=</tt> is there to remind you that this isn't Haskell.<br />
<br />
It's important to note that any kind of value may be put into value boxes, including IO actions and functions.<br />
<br />
Try doing this with a spreadsheet: <tt>fIncls := [get(ve) * get(vVat) | ve <- vExcls]</tt>. Or this: <tt>fIncl1 := apply(get(vVatFunc), get(vExcl1))</tt>.<br />
<br />
If you're wondering why I'm not using Haskell syntax, it's to focus on the meaning of boxes rather than what the functions and combinators mean. That said, this pseudo-imperative syntax is on its way out as it's getting too clunky (that <tt>apply</tt> function is really just ugly). For a quick peek ahead the last few examples would be something like this in reactive-banana:<br />
<br />
<haskell>fIncls = map (\ve -> (*) <$> ve <*> fVat) vExcls<br />
fIncl1 = fVatFunc <*> vExcl1</haskell><br />
<br />
== Events ==<br />
<br />
Let's say we want to build the worlds worst synthesizer. We have 7 buttons: &ldquo;a&rdquo;, &ldquo;b&rdquo;, &ldquo;c&rdquo;, &ldquo;d&rdquo;, &ldquo;e&rdquo;, &ldquo;f&rdquo; and &ldquo;g&rdquo;. Our output is generated by sampling a box twice per second and playing the frequency in the box until the next sample is taken.<br />
<br />
This can't be expressed with the crude formula and value boxes system we've had so far. There is no way to express key presses in that system, a key press isn't like changing a value, it's something that occurs on a specific point in time but after it occurs it's forgotten (your keyboard doesn't remember key strokes, at least mine doesn't).<br />
<br />
In this new system we'll forget about formula boxes and value boxes and introduce event boxes. Event boxes are like formula boxes in that they can refer to the value of other boxes. Event boxes can also react to events.<br />
<br />
Events can be thought of like signals in something like D-Bus. Multiple things (event boxes) can listen to them and do something once a specific event is fired (triggered).<br />
<br />
Every event has a value associated with it. Sometimes the value isn't important because the fact that the event has occurred is what's interesting but often we do want to know the value.<br />
<br />
Events come in streams. When we say event box ''b1'' changes to the value of event ''e1'' when it receives that event we're actually saying that whenever an event from the stream of events we colloquially call ''e1'' comes ''b1'' changes to the value of that event.<br />
<br />
Yes, that's confusing so I'll try to be precise. Just remember that when I refer to something like ''e1'' when defining an event box it's always to a stream of events, never a specific event.<br />
<br />
If you're puzzled by the stream just think of it as an acknowledgement that a certain kind of event can occur multiple times. It actually goes a lot deeper than that, involving those confusing <tt>[(t, e)]</tt> types, but for now just remembering that a kind of event can occur multiple times with possibly different values is good enough.<br />
<br />
Events have values and we can use that to chose to do something only for events with some value. So not only can we determine which streams of events we'll do something with when defining an event box, we can also determine for what values of events we'll do something.<br />
<br />
For example if we have an event that directly sets our synthesizer frequency we can apply a filter that only allows events with frequencies that are pleasant to the human ear.<br />
<br />
== Some reactive-banana syntax ==<br />
<br />
Expressing event handling with the pseudo-code I've used before is tricky and gets near impossible soon. So it's a good thing that once you've understood or at least got a basic idea of the concepts of event streams and event boxes the syntax of reactive-banana starts to make sense. In this section I'll explain the most fundamental functions and operators.<br />
<br />
If you're reading the [http://hackage.haskell.org/package/reactive-banana-0.5.0.0 reactive-banana 0.5 haddocks] there are a few things to keep in mind. The first is that what I've called an event box in the previous section is called a Behaviour in reactive-banana. To avoid confusion I'll stop using the term event box from here on.<br />
<br />
In the reactive-banana haddocks you'll find a lot of references to time-varying functions and lists involving time variables. Just ignore those, they're important but we'll get to them later. As a general rule just ignore what you don't understand.<br />
<br />
You'll also notice a <hask>t</hask> parameter on the <hask>Event</hask> and <hask>Behavior</hask> types. It's basically similar to the <hask>s</hask> parameter for <hask>STRef</hask>, it's a trick to use the type system to prevent constructs that would result in undefined or incorrect behavior. Just ignore it.<br />
<br />
For understanding the next sections you'll need to know about a basic subset of reactive-banana which I'll explain here. First up: event streams.<br />
<br />
=== Events ===<br />
<br />
Event streams are represented by the type Event in reactive-banana. The type <hask>Event t Int</hask> means a stream of events carrying Int values.<br />
<br />
There are three basic things you can do with just event streams. You can transform the events in them, you can filter in events in them and you can combine the event streams.<br />
<br />
Transforming an event stream means changing the values carried by the events in them. As this is ''Functional'' Reactive Programming the streams themselves are not changed. When you transform a stream you create a new stream. Whenever an event in the old stream is fired an event in the new stream is also fired, but with a different value.<br />
<br />
Transforming an event stream is done primarily by good old fmap. The expression <hask>show `fmap` eInt</hask> (or with the (<hask><$></hask>) operator <hask>show <$> eInts</hask>) with ''eInt'' having the type <hask>Event t Int</hask> creates a new event stream of the type <hask>Event String</hask> with the int in every event in the original stream being a string in the new stream.<br />
<br />
To replace the value of an event (if the event doesn't carry a useful value) just use (<hask><$</hask>): <hask>"MOO!" <$ eWhatever</hask> causes every value in the stream eWhatever to be replaced by MOO!. Like (<hask><$></hask>) this is an operator from Control.Applicative.<br />
<br />
Filtering is done using the <hask>filterE</hask> function. When you filter an event stream you create a new event stream with the same associated values but which doesn't contain all the events from the original stream. To only deal with events with positive integers you can create a filtered stream using <hask>filterE (>= 0) eInt</hask>.<br />
<br />
Combining event streams creates a new event stream with all the events from both streams. So if you combine ''eOne'' and ''eTwo'' into ''eThree'' there will be an event in ''eThree'' for every event in ''eOne'' and for every event in ''eTwo''.<br />
<br />
Combining is done with the union function: <hask>eThree = eOne `union` eTwo</hask>. Beware however that when events come in at the same time things can get a little tricky, you'd have to wonder in what order the events are processed. Reactive-banana contains several functions to handle simultaneous events. For the purpose of this page we'll do the easiest thing and ignore simultaneous events. In real world code you would need to think about it.<br />
<br />
=== Behaviors ===<br />
<br />
To create a behavior (event box) in reactive-banana you'll typically use one of two functions: <hask>stepper</hask> and <hask>accumB</hask>. Both work with an initial value and an event stream. The difference is that when an event occurs <hask>stepper</hask> changes the value of the behavior to the value in the event while <hask>accumB</hask> applies the function in the event to the value of the behavior.<br />
<br />
<haskell>eNewVal :: Event t Int<br />
bSet :: Behavior t Int<br />
bSet = stepper 0 eNewVal<br />
<br />
eUpdater :: Event t (Int -> Int)<br />
bUpdated :: Behavior t Int<br />
bUpdated = accumB 0 eUpdater</haskell><br />
The expression <hask>bSet = stepper 0 eNewVal</hask> creates a behavior named ''bSet'' with initially value 0. Once an event from the ''eNewVal'' stream comes in the value of ''bInt'' changes to the value in that event. So if an event comes in with value 2 the value of bSet becomes 2.<br />
<br />
On the other hand the expression <hask>bUpdated = accumB 0 eUpdater</hask> makes ''bUpdated'' a behavior with initially the value 0 but which gets updated (modified) whenever an event comes in. If an event comes in with value (+1) (a slice, so <hask>\x -> x + 1</hask>) and the current value of ''bUpdated'' is 1 the new value becomes 2.<br />
<br />
That's basically it for behaviors. Well, there's a third way to create behaviors: using <hask>pure</hask>. To create a behavior with the value 1 which doesn't change at all use <hask>pure 1</hask>. In case you didn't know, for applicative functors (which behaviors are) <hask>pure</hask> is what <hask>return</hask> is for monads.<br />
<br />
To create a behavior that's depends on old behaviors (<hask>f3 := get(f1) + get(f2)</hask> in our old formula box syntax) we have to use applicative functor functions in reactive-banana. There is unfortunately no option to use monad syntax. To express that the value of ''b3'' is the sum of the value of ''b1'' and the value of ''b2'' we write: <hask>b3 = (+) <$> b1 <*> b2</hask>.<br />
<br />
== Example: the worlds worst synthesizer ==<br />
<br />
Now for an example. We'd like to create a synthesizer. The synthesizer will use our keyboard for input, which we notice through a stream of events called ''eKey'' with as associated value a Char containing the key that was pressed. Something outside our program (and scope of discussion) samples the behavior ''bNote'' every 100ms and plays the tone currently in there until the next sample time.<br />
<br />
To avoid getting caught up in music theory (read: I'm lazy and can't be bothered to look up tone frequencies) the note to play is expressed as an algebraic data type.<br />
<br />
<haskell>type Octave = Int<br />
data Pitch = PA | PB | PC | PD | PE | PF | PG<br />
data Note = Note Octave Pitch<br />
<br />
-- Type signature for the key event, it comes from outside our<br />
-- system.<br />
eKey :: Event t Char</haskell><br />
You'll notice the octave. To change the octave we'll use the '-' and '+' keys. To set the pitch we'll use the 'a'..'g' keys on the keyboard. Never mind that it's really annoying to play with those keys as they're scattered all over the keyboard, this is about the FRP logic not practicality.<br />
<br />
Those chars in the ''eKey'' event stream need to be translated to pitches. Here's one way to do that.<br />
<br />
<haskell>ePitch :: Event t Pitch<br />
ePitch = (PA <$ filterE (=='a') eKey) `union`<br />
(PB <$ filterE (=='b') eKey) `union`<br />
... <br />
(PG <$ filterE (=='g') eKey)</haskell><br />
The &ldquo;trouble&rdquo; here is that we're filtering the stream multiple times, not very efficient. Here's a better way.<br />
<br />
<haskell>table = [('a', PA), ('b', PB), ..., ('g', PG)]<br />
ePitch = filterJust $ (\e -> lookup e table) <$> eKey</haskell><br />
The <hask>filterJust</hask> function is a simple helper in reactive-banana. It filters out <hask>Nothing</hask> events and returns the value inside the <hask>Just</hask> constructor for <hask>Just</hask> events. To get ''ePitch'' we first look up the characters in the translation table and then remove all events who's chars aren't in the table, removing the <hask>Just</hask> wrapper from events who's chars are in the table at the same time.<br />
<br />
The ''bNote'' behavior will not use these events directly, instead ''bOctave'' and ''bPitch'' will each store part of the note and ''bNote'' will combine the information.<br />
<br />
<haskell>eOctChange :: Char -> Maybe (Octave -> Octave)<br />
eOctChange c = case c of<br />
'+' -> Just (+1)<br />
'-' -> Just (subtract 1)<br />
_ -> Nothing<br />
<br />
bOctave :: Behavior t Octave<br />
bOctave = accumB 0 $ filterJust (eOctChange <$> eKey)<br />
<br />
bPitch :: Behavior t Pitch<br />
bPitch = stepper PC ePitch<br />
<br />
bNote :: Behavior t Note<br />
bNote = Note <$> bOctave <*> bPitch</haskell><br />
If you understand what's going on here you should have a basic idea of what FRP is in practice. There are of course considerations in the real world that we've skipped over here, such as how to get the keyboard event and how to play the sounds. To get a better idea of what FRP in the real world looks take a look at the [http://www.haskell.org/haskellwiki/Reactive-banana/Examples reactive-banana examples], they should be easy to follow.<br />
<br />
When following those examples you'll come across the (<hask><@</hask>) and (<hask><@></hask>) operators. I'll give a short introduction here to make it easier to understand the examples. The (<hask><@</hask>) operator is used like this: <hask>e2 = b1 <@ e1</hask>, if an event in stream ''e1'' comes in the value of that event is replaced in the ''e2'' stream by whatever value is in ''b1'' at the time. The (<hask><@></hask>) operator is used in much the same way, but it doesn't replace the value from ''e1'' outright but uses it to compute a new value.<br />
<br />
<haskell>bOne :: Behavior t Int<br />
bOne = pure 1<br />
<br />
bPlusOne :: Behavior t (Int -> Int)<br />
bPlusOne = pure (+1)<br />
<br />
eAlwaysOne, ePlusOne :: Event t Int<br />
eAlwaysOne = bOne <@ eWhatever<br />
ePlusOne = bPlusOne <@> eInt</haskell><br />
<br />
== Time-varying values and functions ==<br />
<br />
If you've read about FRP before you're likely to have come across the term &ldquo;time-varying function&rdquo;. This sounds difficult, but once you understand the basics of behaviors and events it's really no big deal.<br />
<br />
Here's the clue: a behavior contains a value, but the value can change. Therefore at different points in time a behavior can have different values. So we could say that a behavior has a value that varies in time.<br />
<br />
We could also throw away the concept of boxes and say a behavior ''is'' a value that varies in time. This is more correct, those boxes are helpful as teaching concepts but once we talk directly about time they are no longer needed.<br />
<br />
So, a time-varying value is simply a behavior as behaviors can have different values at different points in time. A time-varying function is also just a behavior, one where the value is a function (functional programming 101: the clue to every riddle is that functions are values).<br />
<br />
To go further down the rabbit hole a time-varying value can actually be thought of as a function by making time explicit. If a behavior has value 1 up to the 30th's second and from that point forward value 2 we could express the behavior as: <hask>\t -> if t < 30 then 1 else 2</hask>. This is important: by making time explicit we can reason about behaviors as if they were pure functions. While in practice we're dealing with applicative functors (or in other libraries monads or arrows) we can think of behaviors as pure functions.<br />
<br />
Real world behaviors aren't as simple as from 30 seconds onwards change to value 2. They interact with events. So to express such behaviors as pure functions events need to be expressed in a way that works for pure functions. This is where the <hask>[(t,e)]</hask> type comes in. We can see events as a list of values at certain points in time, for example <hask>[(10, 1), (20, 2), (30, 3)]</hask> for events that occur on second 10, 20 and 30 with values 1, 2 and 3 respectively.<br />
<br />
When viewing events in such a way it becomes easy to create a behavior that changes to whatever value was last:<br />
<br />
<haskell>type Time = Int<br />
stepped :: [(Time, Int)] -> Time -> Int<br />
stepped es t = case takeWhile (\(t', _) -> t' < t) es of <br />
[] -> 0 <br />
xs -> snd (last xs)</haskell><br />
For once this is actually runnable code. If we invoke it as <hask>stepped [(10,1),(20,1),(30,1)] 2</hask> the result is 0, if we invoke it as <hask>stepped [(10,1),(20,1),(30,1)] 12</hask> the result is 1, as expected.<br />
<br />
Stepped sounds a lot like stepper and we can create that function by making a few small adjustments.<br />
<br />
<haskell>type Time = Int<br />
stepper :: a -> [(Time, a)] -> (Time -> a)<br />
stepper d es = \t -> case takeWhile (\(t', _) -> t' < t) es of<br />
[] -> d<br />
xs -> snd (last xs)</haskell><br />
If you understand this bit, why behaviors and events can be expressed by making time explicit you have a good intuition of what FRP is.<br />
<br />
== Making the example runnable ==<br />
<br />
After I wrote this page I got questions about how to actually run the reactive-banana examples. Here's a big block of code that can be pasted into a file and run:<br />
<br />
<haskell>module Main where<br />
<br />
import Data.Char (toUpper)<br />
import Control.Monad (forever)<br />
import System.IO (BufferMode(..), hSetEcho, hSetBuffering, stdin)<br />
import Reactive.Banana<br />
import Reactive.Banana.Frameworks.AddHandler<br />
import Reactive.Banana.Frameworks<br />
<br />
type Octave = Int<br />
<br />
data Pitch = PA | PB | PC | PD | PE | PF | PG<br />
deriving (Eq, Enum)<br />
<br />
-- Mapping between pitch and the char responsible for it.<br />
pitchChars :: [(Pitch, Char)]<br />
pitchChars = [(p, toEnum $ fromEnum 'a' + fromEnum p) |<br />
p <- [PA .. PG]]<br />
<br />
-- Reverse of pitchChars<br />
charPitches :: [(Char, Pitch)]<br />
charPitches = [(b, a) | (a, b) <- pitchChars]<br />
<br />
data Note = Note Octave Pitch<br />
<br />
instance Show Pitch where<br />
show p = case lookup p pitchChars of<br />
Nothing -> error "cannot happen"<br />
Just c -> [toUpper c]<br />
<br />
instance Show Note where<br />
show (Note o p) = show p ++ show o<br />
<br />
-- Filter and transform events at the same time.<br />
filterMapJust :: (a -> Maybe b) -> Event t a -> Event t b<br />
filterMapJust f = filterJust . fmap f<br />
<br />
-- Change the original octave by adding a number of octaves, taking<br />
-- care to limit the resulting octave to the 0..10 range.<br />
changeOctave :: Int -> Octave -> Octave<br />
changeOctave d = max 0 . min 10 . (d+)<br />
<br />
-- Get the octave change for the '+' and '-' chars.<br />
getOctaveChange :: Char -> Maybe Int<br />
getOctaveChange c = case c of<br />
'+' -> Just 1<br />
'-' -> Just (-1)<br />
_ -> Nothing<br />
<br />
makeNetworkDescription :: Frameworks t<br />
=> AddHandler Char<br />
-> Moment t ()<br />
makeNetworkDescription addKeyEvent = do<br />
eKey <- fromAddHandler addKeyEvent<br />
let<br />
eOctaveChange = filterMapJust getOctaveChange eKey<br />
bOctave = accumB 3 (changeOctave <$> eOctaveChange)<br />
ePitch = filterMapJust (`lookup` charPitches) eKey<br />
bPitch = stepper PC ePitch<br />
bNote = Note <$> bOctave <*> bPitch<br />
eNoteChanged <- changes bNote<br />
reactimate' $ fmap (\n -> putStrLn ("Now playing " ++ show n))<br />
<$> eNoteChanged<br />
<br />
main :: IO ()<br />
main = do<br />
(addKeyEvent, fireKey) <- newAddHandler<br />
network <- compile (makeNetworkDescription addKeyEvent)<br />
actuate network<br />
hSetEcho stdin False<br />
hSetBuffering stdin NoBuffering<br />
forever (getChar >>= fireKey)</haskell><br />
If you compare this to the previous example you'll notice some changes in the events and behaviors. This version is more real-world, there are bounds checks and some abstraction (<hask>filterMapJust</hask>).<br />
<br />
The parts answering the question &ldquo;how to run it?&rdquo; are all in <hask>makeNetworkDescription</hask> and <hask>main</hask>. In reactive-banana you first create a description of an event network, then compile that network, enable it and call your normal Haskell event loop. At least, that's the case when you don't use a GUI framework with reactive-banana integration, if you use the wx integration for reactive-banana the event loop is already written for you and some other details are different. See the [http://www.haskell.org/haskellwiki/Reactive-banana/Examples examples].<br />
<br />
All the events and behaviors live in what reactive-banana calls an event network. It's not possible to use behaviors outside this network, you can't for example see inside a behavior from IO code. You can use events though and that's how you couple the FRP stuff inside the event network to the outside world.<br />
<br />
To create an event that you can fire from outside the event network use <hask>newAddHandler</hask> in the IO monad. It gives you two things, an <hask>AddHandler</hask> value and an IO action that takes a value and fires an event with that value. By passing the <hask>AddHandler</hask> value to <hask>fromAddHandler</hask> (inside the <hask>NetworkDescription</hask> monad) you'll get an event stream which you can use in a normal fashion.<br />
<br />
To handle output events use <hask>reactimate</hask>, pass it an event stream containing IO actions and whenever an event from that stream occurs the action is executed. You'll pretty much always want to use <hask>reactimate</hask> with (<hask><$></hask>)/<hask>fmap</hask> to generate those IO actions.<br />
<br />
Once the network description is complete you can compile it. This gives you back an <hask>EventNetwork</hask> value. You can start the <hask>EventNetwork</hask> with <hask>actuate</hask>. This sets things up so that events can actually be received.<br />
<br />
In our roll-your-own program we'll use <hask>getChar</hask> (after turning off echo and buffering on the standard input stream) to receive characters. When a character is received the ''bNote'' is updated and a message is printed with the new value (actually playing a tone appears to involve more code than I'd like to include here).<br />
<br />
Wait? Didn't I say we can't actually observe the value of a behavior? So how do we know which note to play? Turns out reactive-banana has a nice little function called <hask>changes</hask>. When used on a behavior it returns an event stream which contains the new values whenever the behavior is updated. This event stream is passed to <hask>reactimate</hask> to trigger the prints.<br />
<br />
== A broader view of FRP ==<br />
<br />
FRP is a field which is currently in active development, many different approach are being tried and no real standard has been found yet. The [http://hackage.haskell.org/packages/archive/pkg-list.html#cat:frp FRP category on hackage] has a lot of different packages with varying approaches to implementing FRP. Some focus on applicative functors, some on monads and others on arrows.<br />
<br />
Semantics can be subtly or not-so-sublty different between FRP libraries and sometimes naming is different as well (for example signal instead of event).<br />
<br />
In this page I've tried to explain FRP using one specific library (reactive-banana). While this makes things simpler for getting an idea of FRP it can give some wrong impressions due to conflating the limitations of reactive-banana and that of FRP in general.<br />
<br />
[[Category:FRP]] [[Category:Tutorials]]</div>Fa-mlhttps://wiki.haskell.org/index.php?title=Nitpicks&diff=60000Nitpicks2015-08-24T17:17:36Z<p>Fa-ml: scheme-like identifiers</p>
<hr />
<div>[[Category:Language]]<br />
[[Category:Proposals]]<br />
<br />
This page is for people to record nitpicks about the Haskell language.<br />
<br />
A "nitpick", in this case, is something that is annoying or could be improved, but is probably not important enough to justify the added complexity of tacking it on as an extension or breaking existing code.<br />
<br />
In other words, if we could go back in time and fix it before it happened, we probably would, but now it would probably be too onerous.<br />
<br />
Ideally, these nitpicks could help to inform future proposals or compatibility-breaking changes to the language. Even if they may be too onerous to change right now, it's possible that it would make sense to address them at some other time.<br />
<br />
If the nitpick has been discussed at length, please post a link to the discussion.<br />
<br />
== Syntax-related nitpicks ==<br />
<br />
* Re-naming <code>data</code>, <code>newtype</code>, and <code>type</code> to <code>type</code>, <code>newtype</code>, and <code>alias</code>, respectively. See https://mail.haskell.org/pipermail/haskell-cafe/2015-August/120724.html .<br />
* Replace the special if-then-else syntax with a standard prelude function. See https://wiki.haskell.org/If-then-else .<br />
* Introduce a newtype/data with the symbol <hask>::=</hask> instead of <hask>=</hask>, as this is confusing with the equal sign. See https://mail.haskell.org/pipermail/haskell-cafe/2015-August/120724.html<br />
* A type should be introduced with the symbol <hask>:</hask> instead of <hask>::</hask> as in many other languages and mathematical papers. Conversely <hask>::</hask> should be used as the cons operator.<br />
* The kind for inhabited types <hask>*</hask> is not an operator. See https://ghc.haskell.org/trac/ghc/wiki/DependentHaskell/Phase1#ishardtoparse<br />
* <hask>default</hask> is a useful name for a variable, but it's taken up as a keyword for the rarely used defaulting declaration. DefaultSignatures adds a more useful use though.<br />
* Allow hyphenated (à la scheme) identifiers like <hask>example-identifier</hask>, which some of us prefer to <hask>uglyCamelCase</hask>.<br />
<br />
== Semantics-related nitpicks ==<br />
<br />
== Base-related nitpicks ==<br />
<br />
* Re-naming <hask>fmap</hask> to <hask>map</hask>. This has been discussed at length; see http://stackoverflow.com/questions/6824255/whats-the-point-of-map-in-haskell-when-there-is-fmap/6824333 and https://mail.haskell.org/pipermail/haskell-prime/2006-August/thread.html<br />
* Cutting up <hask>Num</hask>, which is a mess of various operations one may not want to all define on some type; for example <hask>(+)</hask> makes sense for vectors in ℝ³ but <hask>(*)</hask> doesn't. Also, <hask>fromIntegral</hask> is useful for some types where the full complement of numeric operators aren't.</div>Fa-ml