KDB+, Elm and web sockets

In the KDB+ implementation of the Conway’s Game of Life that I presented in my previous post there was one element missing – a GUI that would display the results of the simulation. Since I have been planning to have a look at Elm for a while, I checked if I can set up KDB+ talking to an Elm application and it turned out it is very easy to do – with web sockets.

Elm is a functional programming language that compiles to HTML, JavaScript and CSS code intended to run in a browser. The declared paradigm for Elm is Functional Reactive Programming. FRP is not exactly what it used to be back in the days of Conal Elliot and Paul Hudak’s original work. It is now more of a buzzword covering more and more semantic area. The key concept in the  Elm’s take on FRP are signals. A Signal a type in Elm represents a value of type a that changes in time. Signals can be thought of as streams of discrete events carrying values. They can be combined, filtered, counted and so on. Ultimately we obtain a value of type Signal Element that can be displayed in the browser (possibly in a div if one embeds an Elm application this way). The Elm site contains a very convincing argument on why all this is a good idea.

Elm is an actively developed and young language – the development started in 2011. The Elm code that I quote below does not compile with the latest compiler release (0.12.3) as of time of this writing due to a bug in the WebSocket library that I stumbled upon. I tested the code with a development snapshot of the Elm compiler straight from GitHub after the bug was fixed, so it should work fine with the next compiler release.
So let’s talk about the code. What I want is to have the browser connect to the life.admin component (that collects the information about the state of the grid cells) and display the results of the simulation as a grid of white or black squares. Using web sockets is very simple both on the q side and the Elm side. In order to allow the browser to connect to the q process one needs to overwrite the built in .z.ws function. I do it as follows:

.admin.wsh:0;
/ overwrite z.ws
.z.ws:{
  .log.info[`admin] "web socket connection, command ",.Q.s1 x;
  .admin.wsh:neg .z.w;
  .admin.wsh .admin.bToString (.admin.gridi;.admin.gridj)#1b;
  };

The .z.ws function runs when a client connects to the KDB+ web socket interface. When .z.ws runs the variable .z.w is available containing the handle that we can use to send strings to the web socket. As KDB+ supports only asynchronous web sockets for now, I store a negative of that handle in the global .admin.wsh. I immediately use that handle to send a grid filled with ones to the browser (converted to a string by the .admin.bToString function), just to see some action on the connection event.
Then in the function that receives state updates from the grid cells there is a line

if[.admin.wsh<0;.admin.wsh .admin.bToString .admin.states t];

which sends the current grid state to the browser as a string whenever there is someone connected. That’s pretty much all on the q side.
On the Elm side things are simple enough as well

import String
import WebSocket as Ws

main = dispGrid  Signal String -> Signal String
helper = Ws.connect "ws://localhost:17400"

dispGrid:String->Element
dispGrid s = flow down (map dispStr (String.split "," s))

dispStr:String->Element
dispStr s = flow right (map dispChar (String.toList s))

dispChar:Char->Element
dispChar c = (if c=='1' then color black else color white) (spacer 30 30)

This connects to the server at port 17400 and displays strings that are sent from it, parsing them as comma separated lines of characters “0” and “1”. After putting this code in the life.elm file and compiling with elm --make --bundle-runtime life.elm I get a standalone life.html file.

If you want to play with this

all code is on GitHub.

To see the simulation start the life.admin component (see my previous post for details)

yak start life.admin

Then load the life.html file into a browser. Upon connection it should display the grid as a black square. Then start the grid cell processes:

yak start grid

For larger grids the system takes quite a long time to start and set up connections. For example for the 12 by 12 grid it takes about 2 minutes. I’m not sure what is the reason it takes so long. The first couple of generations are also rather slow – about 1/sec. However, after about 100 generations the speed improves and on my (virtual) machine I get about 70 generations per second.

Here is how the start of the simulation looks like in the browser:

LifewithEC_Elm

 

And a bonus: a one-line implementation of Conway’s Game of Life in q.

P.S. 2016-05-11 The paragraph on Elm is obsolete now. In the 0.17.0 release Elm did away with signals and replaced them with “subscriptions”.

Advertisements

Tags: , ,

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s


%d bloggers like this: