In this blog I talk about some of the personal programming I do as a hobby. From Java to Rust via Haskell, I've played around with a lot of technologies and still try to have fun with new languages and APIs!
A few days ago this blog entry sparkled a big discussion on Reddit, and it got me thinking that I just couldn't be relying on my 20 years experience in professional programming if I ever needed another job. I need to practice small, low level coding problems.
So of course I decided to use Rust. I'm putting my code on Github so feel free to have a look if you're interested. I tried to not look at existing resources, I'm sure you can find plenty of Rust interview answers and toy problems if you look around :-).
First I tackled some array operations like finding and removing duplicates, implementing quicksort, etc. I just used Vec and implemented the algorithms only. In some cases of course a Set is what makes sense (finding duplicates) so I just used another vector as a set, of course implementing an efficient integer set would a good problem too. Here I didn't run into any major issue.
The second (and last, for now) thing I did is to implement a Linked List from scratch. The list owns its values of course, so implementing pop/push methods and iterator support proved "interesting"! Now I really had to understand the borrow checker, owning vs referencing, etc. I even tried to do thing using unsafe code like Box::into_raw! And? Well, my program... crashed. I think I'll tread carefully if ever I need to use unsafe.
In the end, mem::replace was my savior. I could get and own a cell from my list by swapping it with an empty cell, do whatever I needed to do, and reset the cell to a proper value. That worked a charm!
So, I'm still happy enough with Rust. The error messages are for the most part clear enough to be able to understand, I do find enough on the web between the official docs and Stack Overflow to save me from being stuck. Rust is good!
From time to time I do a little bit of fooling around with algorithms and AI, I suppose it's a break from what I do in work, which is more about building business applications. I don't have a real goal in mind, I don't think I'm going to stumble about an algorithm for general intelligence or something, but I like to understand how things work at a low level. So I've writing a bit of Rust code to implement some linear algebra (some matrix and vector operations) and use that to build some small neural networks. You can find the current state of that code here. Of course, if you really want to use production ready code for linear algebra you should check https://www.rustsim.org/ and if neural networks and AI in Rust are what you're after please check https://github.com/AtheMathmo/rusty-machine. Note that rusty-machine is still in a state of flux since it's using its own linear algebra library but there's talk about using nalgebra from rustsim hopefully that will bring together all these initiatives in one unified Rust platform for numeric operations and AI. I have to say I'm still impressed with Rust. I like that you can do a lot of things with a functional approach, while still being able to update variable values or do other imperative operations when it makes sense. It does feel a lot like "pragmatic Haskell" at times. So far I haven't struggled with the borrow checker, but the code I've written so far is fairly simple and self-contained. As always, I'm still wondering if there are some projects that it would make sense for me to contribute too. I'm certainly not a AI or math expert, but if you have a Rust project that could do with some contributions, let me know! Happy Rust Hacking!
I just downloaded the game Lovecraft Quest on my Android tablet, and was enjoying the puzzles, until I got to the final one, and that got me, ahem, *frustrated*. I found a walk-through where the reviewers admitted to more or less clicking randomly on the screen for one hour until it worked:
I actually managed to solve the puzzle the first time quickly with sheer luck, but on the second run I was stumped. So I followed the only reasonable course of action: let the computer solve the puzzle for me!
The puzzle is as follows: there is a square (4 rows, 4 columns) of gold bars that can be either in horizontal or vertical position. You can make one bar pivot, but when you do that all the bars in the same row and column pivot too! You need to get all bars to the vertical position for the door to open to reveal... Cthulhu itself!
So let us use Rust for this puzzle, and see if a brute force approach can work.
Let's first define a few types. A grid is a 4x4 array of booleans and a position is a tuple. We'll have positions ranging from (0,0) to (3,3). A grid is solved is all elements are true (so true means vertical position for a bar).
Then let's implement the swapping operation. We'll take one Grid reference and return a new Grid with the proper bars swapped.
Note that we swap again the position we chose since we swapped it twice already, one for the columns and once for the rows. Not very elegant maybe but simple
The main solving function is as follows: we're given a grid and we return a list of positions to swap to solve the puzzle. If the grid is already solved we return an empty vec. Otherwise we keep two structures: a map of grids to a vector of positions (showing how we got to that particular grid from the start grid) and a list of grids to process. We use a Deque here so we can put new grids at the end but process grids from the start, to do a breadth-first traversal of all possible grids.
The try_all function will do all possible swaps on the given grid and store all the results with the path used to get to them. We store for all grids the shortest path we used to get to it. New grids get added at the end of the todo list. We return the path if we end up with a winning grid.
To simplify calling the program, we'll just pass a string made of 16 characters, with 1s and 0s indicating the position of the bars we see on the screen. Parsing this string into a Grid instance is easy enough with the help of chunks():
And we can pass then that string as a argument to our binary program, and print the result:
In my case, the program ran and gave me the solution: only 12 moves!
This Rust code is probably fairly naive in places, since I only have a couple of weeks of evenings learning it. I'm not too happy with the number of clone() calls I had to add to make the borrow checker happy, on top of the ones I thought I needed anyway. Maybe immutable structures would in fact be easier to use here! Of course this code could be made parallel but since it gave me my answer in a few seconds I didn't need to improve it further.
I'm currently using
Visual Studio Code with the Rustextension.
It's sufficient for the little exercises I've been doing so far, but I notices
that code completion is not very accurate and does not seem to give me
everything that's possible.I've
installed the IntelliJ Rust extension in my community IDEA, I'll see how well it works when I start doing bigger
projects.
Rust is obviously a
different kettle of fish than the last language I picked up, which was Go. It's
a lot more complex and rich and hopefully powerful, and consequently takes a lot more time to master.
It feels a bit like a cross between C for the low level aspects and Haskell for
the structural and functional parts. I was a bit surprised straight away to
read about variable shadowing since it seems to take away the security somehow (you cannot mutate a variable
but you can redefine it), but from what I read it doesn't seem to be an issue
practically since the compiler holds your hand at all time.
Most languages I've
worked with have a Garbage Collector, so I'd say dealing with the borrow
checker is going to be fun in larger code bases, but so far in the small
exercises I've done it hasn't been an issue.
Hopefully I can get
productive with Rust quickly, I'd like to contribute to projects like Rusty-Machine to do neural networks and ML with Rust, which would seem a perfect match with
its performance and safety. We'll see!
I've put a littleproject on Github written in Go. It's a little database system that allows
writing and reading objects, and do GraphQL queries on them. The main principle
is that objects have a arbitrary String ID that is like a path, separated by
slashes, and deleting an item with a given ID deletes also items with
"children" ids.
For fun, I used
Cassandra as the main data store, since it's optimized for fast writes and
loads of data; we never delete anything, we just keep every state of an object
as history. Text searches are done on the last version of objects using
Elastic. GraphQL support allows to follow object namespace relationships.
I also provide
Dockerfiles to deploy either just the database systems for testing, or the
whole application.
I'm not sure this
can be useful as is for anybody, but this was for me to try Go on a real-life
project. Apart from the gotchas I've wrote about before, it was a rather
painless and enjoyable experience.
As I wrote my first non trivial project in Go, I had a few head-scratching moments. Nothing that a quick search could clear up, but worth keeping in mind...
You may run into that one quickly enough in tests. An instance of an interface can have a nil value but since it carries the interface type information, it does not equal to nil!! A lot has been written about it so make sure to read about it!
Redeclarations
The fact that you can use := to declare variables easily is a double edged sword, as declaring a variable with the same name as a previously declared one is allowed if it's in a different scope, and it shadows the original variable. So:
This code will only print True at the end. The "err" variable inside the if block has been redefined so even though it's not nil inside the if block, it IS nil once you exit it! So if you want to chain several operations that may return errors and then at the end handle whatever error occurred in a consistent way, you have to be careful.
Closures
This one gave more some Javascript PTSD:
This prints : 4 4 4 Which was not what I expected! One easy fix is to add a line saying i:=i before creating the func in the first loop, which by virtue of the previous gotcha redeclares a variable in the scope of the for loop body.
Errors
I'm not convinced in the end by the standard error reporting in Go. A lot has been written on that topic too. I feel that the code is peppered with error handling that gets in the way of readability and implementing cleanly the business logic. I'm sure there are some design tricks you can use, but you shouldn't have to resort to tricks to do clean error handling in a language, because at the end of the day it's how you handle errors that make up the quality of your software, not only how you handle the happy path.
These things you can watch out for and probably code around pretty easily, but they do impact a bit the ease of use of Go, even though I still think it's quite a simple elegant language to quickly be productive in.
OK, the title is an easy joke, but that's what happens when you give a silly name to a language… So I've started looking at Golang, since it seems to be the newish (ok, ok, not that new) kid on the block. And in fact the name is not an issue: I usually type "golang" to prefix my searches on the web and it works pretty well. - I installed Go and the first striking thing are the instructions to read "how to write Go code". Having one way to structure the code (one workspace containing source control repositories, each containing packages) makes it very easy to get started - compared say to Java where different IDEs may have different approaches to what a "project" is. I wonder how this structure works when you write Go professionally, and you want to distinguish open sources dependencies from proprietary code. Also coming from Java where you're used to structure classes into packages, seeing Go repositories with a huge number of files inside one folder makes me shudder, but we'll see over time. - I started of course with the Tour of Go. In a couple of evenings I went through it, proving how easy and small the base language is. Encouraging! - I then started to get my hands dirty by writing a little app that hooks together JSON web services, Cassandra, Elastic Search and Docker. It was fairly easy to find libraries and manage to put them to use. I'll probably push that code to Github at some stage after some cleaning up. So Go delivers on the promise to be a language easy to pick up and easy to get started. You can get from zero to productive in a few hours. These are the features that stood up for me: - Lack of generics. It's a trope in the computing world "Go doesn't have generics, ha ha ha". Of course straight away you see that arrays/slices and maps are typed, so already the basic use case for generics (safety in collections) is taken care of. Then you have functions as first-class citizens and interfaces, so there are plenty of techniques you can use to go around the lack of generics, so I'm not sure it's such a huge problem. - Interfaces. It's interesting that there is no explicit declaration that a type implements an interface. If you define a Duck interface with a Quack method, every type that you use as the receiver for an implementation of a Quack function is considered a Duck. This is nice, but still tooling support to find out all types that implement a given interface will be a must ("OK, this function expects anything implementing Duck, what implementation can I use?"). - Pointers. I'm at the core a Java developer, so the idea of pointers makes me a bit uneasy. But I breathed easier when I saw "no pointer arithmetic". In fact, pointers in Go just make explicit if you pass a struct by value or by reference. I feel this adds a level of clarity that is worth the extra syntax and the initial repulsion the word "pointer" may awake in some. - Errors. Go recommends a style where a function that may fail should return a tuple: normal value, error. The calling code can decide to ignore the error or deal with it. This is reminiscent of Either in Haskell. I'm still not sold that this is a better system than checked exceptions (but I seem to be the only one liking checked exceptions it seems), but I'll need more practice before I make my mind up. So all in all I like a lot of design decisions that were made in Go, and it certainly makes for a pleasant programming experience. I ran into a few gotchas that I'll cover maybe in later posts, but nothing too stressful. So far, I have to say I enjoyed the experience! Happy Go Hacking!
I
built a little role-playing game in React Native. I tried to build the type of
game I like playing, with quests and interactions with non-playing characters,
while learning some mobile UI programming tricks.These are some of the main points that I took
away:
The initial setup was a bit
involved, probably because I'm not used to develop JavaScript
applications. Getting the right code to properly do the plumbing between
React, Redux,React Navigation,
tests, etc. was a bit of a hassle. Obviously this has to be done once and
then you can concentrate on writing the functional code. As I noted
recently, then upgrading to newer versions of your dependencies can be a
hassle!
I was happy with my
declarative approach to the game world. I don't think it would be
manageable to do otherwise.I
define as JavaScript structures the world itself: the different places and
how they communicate, the items they contain, etc., the non-playing
characters and the possible interactions you can have with them, items and
their characteristics, monsters and spells. This gives me an immutable
representation of the start world, and the state of an actual game just
has to store the modifications from that initial state
This of course could mean
that I (or somebody else) could reuse the game mechanics for a totally
different adventure!
I of course used of Redux to
manage state. The state is only modified by Redux reducers, so everything
the player does in the UI just becomes actions, not explicit state
management operations. I combine several reducers, each reducer being
responsible for modifying one section of the global state, which makes
each reducer simpler, but fragment the code. For example when the player
takes an item from a room, one reducer adds the item to the inventory,
another removes the item from the room, so maybe there's some potential
for bugs there
I found the integration
between React and Redux easy to use: you simply define the mapping between
the state and components properties, and between component interactions
and Redux actions.
I abused a little bit Redux
to implement combat: combat holds a kind a mini state for each fighting
round, and then the result of a fighting round both is represented in the
UI ("the rats bite you for 2 damage"), and impacts the global
world.
I didn't spend too much time
on the UI, just using basic React Native components. I found some of the
layout hard to do correctly, and styling components is not intuitive when
you're not a CSS expert. Maybe I should take a CSS/Design course, because
you can tell from my UI designs that I'm a programmer :-)
All in all, writing in modern
JavaScript was nicer than expected, even though I think using a stronger
typed language would be better. If I had to do another similar project I
would probably try to use Typescript. I liked especially the object spreads to update parts of structures and the use of consts.
I used Expo to test on a
tablet, I didn't try to actually generate a final application outside of
Expo, I haven't looked at all on how to distribute the game as an app.
All in all, if was an enjoyable experience, but of course designing a full game instead of just a prologue you can do in 5 minutes would be a different type of endeavor...
Some time ago, I wrote a little game using React-Native so I could play around in Javascript with React, Mobile development and Redux. Yesterday I checked this project again on Github, and saw that there was a security issue Github detected and warned me about: the "merge" library had a vulnerability, reported in CVE-2018-16469. OK, time for action!
Of course, my project doesn't reference merge directly. It's a transitive dependency of jest. A quick check on the web showed that since I created the project, a lot of things have happened, so my project dependencies are lagging behind. So hopefully upgrading should solve my security issue.
I find instructions at https://stackoverflow.com/questions/16073603/how-do-i-update-each-dependency-in-package-json-to-the-latest-version, so I run npm outdated, which indeed confirms a lot of my dependencies are old.
I install npm-check-updates: npm i -g npm-check-updates ncu -u
As indicated, and I get: Hmmmmm... this is taking a long time. Your console is telling me to wait for input on stdin, but maybe that is not what you want. Try specifying a package file explicitly with --packageFile package.json. See https://github.com/tjunnone/npm-check-updates/issues/136#issuecomment-155721102
OK, now my game starts again, I suppose I need to test it thoroughly because something may again decide to break... I did enjoy developing the game, but certainly managing the NPM vulnerabilities and the Javascript ecosystem pace of change can be challenging. I know this isn't an original thought, but experiencing it first hand is definitely an eye-opener!
Whoa, nearly two
years since I last put something on this blog. I lost the habit, and since I'm
not involved in EclipseFP anymore I don't have the stream of Haskell news to
report I used to. I will now try to reboot it and try to find interesting
experiences to share!
I was never a big
fan of social media sites, but I use to link to some of these blog posts on
Google +, which is now dying. So this should stay a simple blog, where I have
nothing to sell you and no ads to pester you with!
Over the last few
months I've built a toy project in React Native, started learning Go, and done
a lot of things in my day job, so hopefully some interesting stories will
appear! Stay tuned!
I've realized I haven't written or read a line of Haskell in the past 6 months. After roughly ten years of tinkering with it, it seems that I've given up on it. There is a big obvious reason, and other smaller ones.
Professionally, my job got a lot more challenging (I'm officially an **architect** now, which means I still write lots of code but I have to draw pretty diagrams too (-: ) and involves a lot of research and learning new stuff, things like microservices, docker, messaging, Angular2, mobile apps, etc. So a lot of my time is dedicated to work or to learning for work, so I don't have the time to play around with something quite unrelated like Haskell.
I suppose to be honest there also was a bit of lassitude with Haskell. I got tired of the less than optimal IDEs, I realized Haskell was not going to get me a great job, and there were a few little skirmishes on the web that got ugly and made me see the community in a less favorable light.
This was fun, though, and I certainly learned a lot, and I hope it has made me a better programmer. A lot of my coding now is done in Java 8, and it's good to be able to apply some functional idioms practiced in Haskell, and more general ideas like data immutability, small pure functions do help make better - more testable, easier to understand - code.
So maybe I'll come back to Haskell some day, but not for now. To all the open source projects I've contributed, I wish you the best!
This week was I
suppose fairly typical. Started using a new library, the excellent
sqlg that provides the TinkerPop graph API on top of relational
databases. Found a bug pretty quickly. Off we go to contribute to
another open source project, good for my street cred I suppose. Let’s
fork it, and open the source code in IDEA (Community edition). After
years of hearing abuse about Eclipse, I’m now trying to use “the
best IDE ever” (say all the fan boys) instead. Well, that didn’t
go so well, apparently importing a Maven project and resolving the
dependencies proves too much for IDEA. I fought with it for a while,
then gave up.
Fired up Eclipse, it
opened and built the sqlg projects without a hitch. Wrote a test,
fixed the bug, raised a PR, got it accepted with a thank you, life is
good.
Then I find another
bug. Except that upon investigation, it’s not in sqlg, it’s in
the actual TinkerPop code. The generics on a map are wrong, there are
values that are not instances of the key class (thanks generics type
erasure!). So I can fix by changing the method signature, or change
the keys. Both will break existing code. Sigh…
Oh, and the
TinkerPop project doesn’t build in Eclipse. The Eclipse compiler
chokes on some Java 8 code. Off to the Eclipse bug tracker. Maybe I
need to have three different Java IDEs to be able to handle all the
projects I may find bugs in.
Maybe I didn't look hard enough, but I'm not aware of a tool to generate the contents of the Cabal data-files field automatically when you have loads of folders to include. Cabal has very simple wildcard matching for files references in this field, by design (to avoid including too much data in a source distribution). So it only supports wildcards to replace the file name inside a directory for a given extension, and doesn't support sub directories.
For the reload project - first release on Hackage! - I had to include loads of files, all the Polymer web components the UI depends on, which are all on different sub directories, with a bunch of different extensions. So I wrote a little tool to generate the field automatically, and put it on Hackage too.
You pass it a directory name, possibly some subdirectories and extensions to ignore, and it generates all the required entries. Saved me loads of time, and scratched my own itch!
After giving up on EclipseFP, I've worked a bit on haskell-ide-engine and leksah, contributing little things here and there to try to make the Haskell IDE ecosystem a little bit better. But at some point, I tried to update the GTK libraries on my Ubuntu machine to get leksah to run, and broke my whole desktop. Hours of fun followed to get back to a working system. So I thought again at my efforts last year to have a web based IDE for Haskell, because using the browser as the UI saves users a lot of pain, no UI libraries to install or update!
I started another little effort that I call "reload", both because it's another take on something I had started before and of course because it issues ":reload" commands to ghci when you change files. I have changes the setup, though. Now I use Scotty for the back end, with a REST API, and I use a pure Javascript front-end, with the Polymer library providing the web component framework and material design. I also use a web socket to send back GHCi results from the back end to the browser. I still use ghcid for the backend, maybe one day when haskell-ide-engine is released I can use that instead.
The functionality is fairly simple yet: there is a file browser on the left, and the editor (I'm using the ACE web editor) on the right. There is no save button, any change is automatically saved to disk (you use source version control, right?). On the server, there is a GHCi session for each cabal component in your project, and any change causes a reload, and you can see the errors/warnings in a menu and in the editor's annotations. You can build, run tests and benchmarks, and I've just added ":info" support. The fact that we're using GHCi makes it fast, but I'm sure there's loads of wrinkles to iron out still.
Anyway, if you're interested in a test ride, just clone from Github and get going!
I'm going through a hard pass with Haskell. I still love the language, of course, but some things in the ecosystem bother me as they impact seriously both the fun of writing Haskell and my productivity.
Sometimes it's the lack of good development environment that gets me. I have failed with EclipseFP to build a community and gather enough support, but it doesn't seem that other efforts go that much further. I contribute to Leksah and haskell-ide-engine, and there a plugins now for Atom or other modern editors, but when I do a spot of Android development I see what a good IDE is and how much I miss in Haskell.
But today it's more the open source libraries issues that irks me. It's great that we have loads of libraries, and they're open source and usually good quality. But of course the maintainers are all volunteers, and sometimes have better things to do. But there are a few libraries that I use in my code that now actually stop me from progressing. I have provided enhancements or bug fixes that I need for my projects as pull requests, and they languish in the maintainers' inboxes for months. So what am I to do? Hound the maintainers? Fork the library to apply my patches? Rewrite my code so it doesn't use that library but another, better maintained? Not use libraries but write everything myself? And of course if I offer to take over maintainership I'll end up being overloaded and will perpetuate the problem. I suppose the best approach will be to offer to be one of MANY maintainers for the library, so that I can merge my changes and release on Hackage if the others maintainers are otherwise busy/uninterested. I'm not sure how that can work in the general case, though, if loads of people are maintainers for loads of libraries, I believe that having one person with the vision and the drive for a project is best, but for little libraries it may not matter much.
Oohhh, it's been a while since I've posted. I spent some time working on haskell-ide-engine, but then I got Haskell fatigue and decided to look at Android instead. A change is as good as a rest!
Coming from the Java world, it's not difficult to get into Android. I followed the guide on the Google site to get the basics. At first I got a bit afraid of the unholy mix of Gradle build scripts, visual layout editor, XML files and Java code, but you get over it. The IDE has some nice touches and it's good to get useful autocompletion in resources like ids and strings. I liked the warning about SDK level APIs and missing resources once I started translated my app into French.
But I have to say, when I was working on EclipseFP I often ran into IDEA fanatics that swore that IDEA was miles ahead of Eclipse. Android Studio famously moved from Eclipse to IDEA, and frankly, I don't see what the hype is about. Yes, Eclipse has some annoying bugs and idiosyncrasies. But Android Studio, at least with the default settings, as I haven't spent much time customizing it, is not such a wonderful IDE. It's slow to start up, the view layout is sometimes confusing, the font is too fine or small in places (I must be getting old, but sometimes I couldn't see that a semi colon was in fact a colon) and the warning/error markers in the gutter are way too small and nearly invisible, to the point that sometimes the build fails and I can't see where in the source is the error! Maybe there's a special "grumpy old man with failing eye sight" setting to make things bigger.
Since I believe that you learn by doing, I've developed my first app, and I'm in the process of publishing it to the App Store (so I can claim I'm a published Android developer in my CV, wink). Apart from the fact that you need to supply an icon in 2 million different sizes, which is challenging for somebody with my artistic abilities, it's a straightforward process. My app is an uninteresting workout log app (to record how much weight you supposedly lift at the gym) that's purely local (no social features, so you can't boast online about the weights you may have lifted), but hey, it's a start. The code is of course on Github.
I've also wrote a basic game using the framework presented here, and the nice asset from Kenney (see note about artistic abilities above). Nothing fancy, just a rabbit hopping over holes and getting carrots for points, but just seeing my little game running on my family's phones and tablets is nice! It's on Github too.
I'm still playing with my LSTM networks, inspired by a few blog posts about their "unreasonable efficiency". I spent a lot of time messing with genetic algorithms, but then I came back to more predictable methods, namely gradient descent. I was trying to optimize the performance of the cost function I use via AD (even asking help on stack overflow) when I stumbled across a couple of blog posts on symbolic differentiation (here and here). The last one, combining automatic and symbolic differentiation, struck a chord. If my differentiation calculation was taking so much time to calculate, could I just not calculate it once with symbolic expressions, then close the resulting expression over my variables (my LSTM network) repeatedly while applying the gradients. I should only pay the price for the derivation once!
So I extended the data type suggested in the blog post to include all operations I was using in my function, manage to sort out all the types and verify via a few tests that it would work. I had great hopes! But as soon as I started testing on a real LSTM, the code just crawled to a halt. I even thought I had some infinite loop, maybe some recursion on the expression, but testing more thoroughly showed that it was the sheer size of the generated expression that was the issue. A LSTM of 2 cells is represented in the cost function used by AD as an array of 44 doubles, so basically for a LSTM of 2 cells, I'll have 44 variables in my gradient expression. My simple test that tries to use a LSTM to generate the string "hello world!" uses 9 cells (9 different characters in the string) , which is 702 variables. Even printing the expression takes forever. Running it through a simplifying step takes also forever. So my idea was not as good as it first looked, but it was fun testing it!
The code for my expressions can be found here, and the code doing the gradient descent via the symbolic differentiation is here. All of that looks probably very naive for you calculus and machine learning experts but hey, I'm a human learning... If everybody has any idea to speed up my code, I'l happily listen!
Some weeks ago there was a bit of a tussle over at Reddit, with subreddits going private in protest, talk of censorship, etc. This was interesting to see, from a distance. It got me thinking about trying to replicate Reddit, a site where people can share stuff and have discussions, but without having the server control all the data. So I've developed a very basic Reddit clone, where you can post links and stories and comment on them. You can also upvote stories and comments, and downvote what you upvoted (cancel your upvote). But there's a catch: the site has no database. Things are kept in memory, and on the users machine, via the HTML 5 LocalStorage. That's all!
Everytime you upload or upvote something, it gets saved to your LocalStorage for the site. Once something gets downvoted to zero, it disappear. When you go to the site, whatever is in your LocalStorage gets uploaded and upvoted again. So stories can come and go as users connect and disconnect, and only the most popular stories will always be visible on the site (since at least one connected user needs to have uploaded or upvoted a story for it to be visible).
Of course, there is still a server, that could decide to censor stories, modify text, but at least you can always check that what you have on YOUR machine is the data you wanted. you can always copy that data elsewhere easily for safe keeping (browser developer tools let you inspect your LocalStorage content).
All in all, this was probably only an excuse for me to play with Javascript and Java (I did the server side in Java, since it was both easy to build and deploy) and Heroku. I've deployed the app at https://fivemegs.herokuapp.com and the source code can be found at https://github.com/JPMoresmau/5megs. Any feedback welcome!
Some time ago an interesting article surfaced on Reddit, about using recurrent neural networks to generate plausible looking text. Andrej did a very good job in explaining how they work and some of the techniques and algorithms he used. I thought this was worth some explorations on my own, so I did a bit of research and tried to implement my own networks in Haskell.
I implemented the basics using the hmatrix package to have vectors and matrices. I went to Khan Academy to learn more about these topics because I had stopped math in school before learning matrices. Once I managed to implement hopefully correctly the algorithm I used the simple-genetic-algorithm package (well, my fork, uploaded on hackage) to evolve the network via genetic selection and mutation.
This gave some results, especially when I fixed my mutation code, that in fact was doing nothing, thus emphasizing again that mutation is a critical part of genetic algorithms, and not just crossovers.
Then I went to implement proper learning algorithms, a bit less random than genetic evolution. I was clearly out of my depth there, but learned a lot. To implement gradient descent I actually used the ad library and had to rewrite the algorithms without hmatrix so they would work on simple lists. Given that a couple of weeks again I didn't even understand what AD was, I'm happy I got some stuff to work. I was lucky to find some good code in python, even trying to understand the under-specified RMSProp algorithm.
The end result is not great, though. My network can learn the really complex sentence "Hello world!" and regenerate it after a couple of thousand iterations of the learning algorithm, in around a minute on my machine. I haven't managed to parallelize the treatment yet, and running on all my cores instead of just one make performance a lot worse. On more complex sentences performance becomes really bad, as both the network becomes bigger (more characters to deal with, etc) and the data to evaluate is bigger.
Trying to use a sparse representation for characters using 2 values instead of 1 as in the standard 1-of-k encoding didn't work well. I also realize that tweaks in the cost function had a huge impact on how well and how fast the network can learn. I have started to look at cutting the data in batches but I think I need to make the learning on simple data as fast as possible before moving on.
So, nothing earth shattering, no great progress or insight, but I feel I learned a lot by implementing my own stuff and running into all the issues that are probably well known of people familiar with these subjects. My artificial intelligence is still pretty dumb, but hopefully my own natural intelligence has progressed a bit!
The code is on github of course, so if anybody wants to have a look, I'll gladly take any feedback!!
Hello, after a few years and several releases, I am now stopping the maintenance of EclipseFP and its companion Haskell packages (BuildWrapper, ghc-pkg-lib and scion-browser). If anybody wants to take over I' ll gladly give them all what's required to get started. Feel free to fork and continue!
Why am I stopping? Not for a very specific reason, though seeing that I had to adapt BuildWrapper to GHC 7.10 didn't exactly fill me with joy, but more generally I got tired of being the single maintainer for this project. I got a few pull requests over the years and some people have at some stage participated (thanks to you, you know who you are!), but not enough, and the biggest part of the work has been always on my shoulders. Let's say I got tired of getting an endless stream of issues reports and enhancement requests with nobody stepping up to actually address them.
Also, I don't think on the Haskell side it makes sense for me to keep on working on a GHC API wrapper like BuildWrapper. There are other alternatives, and with the release of ide-backend, backed up by FPComplete, a real company staffed by competent people who seem to have more that 24 hours per day to hack on Haskell tools, it makes more sense to have consolidation there.
The goal of EclipseFP was to make it easy for Java developers or other Eclipse users to move to Haskell, and I think this has been a failure, mainly due to the inherent complexity of the setup (the Haskell stack and the Java stack) and the technical challenges of integrating GHC and Cabal in a complex IDE like Eclipse. Of course we could have done better with the constraints we were operating under, but if more eyes had looked at the code and more hands had worked on deck we could have succeeded.
Personally I would now be interested in maybe getting the Atom editor to use ide-backend-client, or maybe work on a web based (but local) Haskell IDE. Some of my dabblings can be found at https://github.com/JPMoresmau/dbIDE. But I would much prefer to not work on my own, so if you have an open source project you think could do with my help, I'll be happy to hear about it!
I still think Haskell is a great language that would deserve a top-notch IDE, for newbies and experts alike, and I hope one day we'll get there.
For you EclipseFP users, you can of course keep using it as long as it works, but if no other maintainers step up, down the line you'll have to look for other options, as compatibility with the Haskell ecosystem will not be assured. Good luck!