Saturday, August 3, 2013

From Haskell to Processing

I am happy about my last Haskell project. Its name is processing, and it is a library aimed to generate processing.js code. Actually, the purpose is to create interactive web animations, and processing.js is just the selected backend.

inCircles n =
  let t = intToFloat n * 0.03
      r = 100
  in  Circle (r * sin t, r * cos t) 20

I found the process of creating the library both funny and exciting. Phantom types, Template Haskell, Monads, ... I have used all the Haskell artillery to make the library nicer for the user, with some extra work from the developer (me). A lot of work still needs to be done. However, I am going to make it public right now, since it is already capable of working reasonably well.

Some days ago I published one of the output scripts in reddit to make sure that these animations are compatible with different browsers and settings. And it seems that it worked for everyone. Here is the animation I posted (try to move your mouse inside).

The reason I started working on this library is that I was looking for a library to write web animation scripts, without the need of running a server for them. Mainly, because I do not own a web server (I only have a web hosting, where I can upload these scripts). I looked through several choices, and processing.js suited my purpose very nicely.

Levels of abstraction

The library is built by levels of abstraction, and I have allowed the user to use any of the levels, hiding selected entities to make sure the user builds correct processing code. For example, you won't be able to use a variable before it is defined, create a variable twice, or calling a function where it does not make much sense. The compiler will stop you. The library levels are classified in the following form. Each one is built on top of the previous one.

  • Primal. This level is actually hidden in an internal module. It defines the abstract syntax tree of a processing script, how to print it, and other pretty basic stuff. However, it is one of the largest modules. It is the core of the library.

  • Basic. This level exports a writer monad which produces processing code. Imperative feeling. It is not really convenient, but it served me as starting point to work in the next level of abstraction. I exported it since it does not do any damage, and also because it has the property that the generated processing code is predictable.

  • Mid. Full-featured like the basic level, but more convenient. Still imperative feeling, but it makes sense given the nature of processing. It works using events, with things like

    on Draw $ do
       ...
    
    or
    on MouseClicked do $
       ...

    The output processing code produced by this level is optimized using a common-subexpression recognition. It searches for commonly done operations, and create variables for them where they are only done once.

  • Simple. The most convenient level. Haskell-ish feeling. Create values of the Figure datatype (defined in the same module) and let the library decide how to write the processing code for you. It includes several options, like static image displaying, time-dependent animations or even interactive animations (very experimental yet). It is inspired by the gloss library, which I think is the perfect example of easy-to-use animation library.

Using the Simple interface I have created this recursive animation.

You can see the complete code here. More examples are to be added in the future.

Future plans

In the near future some of my planned additions are: arrays, conditional values, pre-made figures, images (the type is there but there is no function to create them) and more examples. I also have to do more testing and check if the library documentation is clear enough for a new user. Any contribution in this regard would be really appreciated. The library code lives in GitHub.

Thanks for reading,
Daniel Díaz.

No comments: