Haskell For Kids: Web-Based Environment Goes Public!

Last time, I described my work on a web-based programming environment for Haskell and Gloss, which is available from github as the gloss-web project. Now you can try it online without having to install it yourself! Here’s the URL:

http://dac4.designacourse.com:8000/

It seems to work fine at least with Chrome, Firefox, and Safari on Linux and Windows. Internet Explorer (even 9) is known NOT to work.

What’s New

I’ve made a few changes to the code and fixed a number of bugs from Sunday’s late-night coding sprint, but the biggest change was to enable use of the SafeHaskell extension. It’s now impossible to circumvent the type system and run arbitrary code on the server. Evidence:

Note that there are still no resource or CPU time limits, so there are no protections against writing infinite loops or infinite data structures, so it’s still possible to use the server to run a denial of service attack against itself. Please don’t do that. I already know you can, and it’s really just not cool. I’ve installed the server on a dedicated otherwise-empty machine I set up and installed for this purpose, so the only people you’ll really be hurting are other programmers like yourself who want to try this demo.

Want a non-trivial example to try it with? Your wish is my command; here’s the simple one I’ve been playing around with as I develop the server:

{- This is my wagon -} import Graphics.Gloss.Data.Picture import Graphics.Gloss.Data.Color picture = pictures [ blank, color brown (translate (-60) (-80) wheel), color brown (translate ( 60) (-80) wheel), color black (translate (100) ( 75) (rotate 45 handle)), color red body ] brown = dark (dark (dark orange)) wheel = pictures [ rotate 0 spoke, rotate 45 spoke, rotate 90 spoke, rotate 135 spoke, rim ] spoke = rectangleSolid 10 70 rim = thickCircle 35 15 body = rectangleSolid 200 100 handle = pictures [ rectangleSolid 100 10, translate 50 0 (rectangleSolid 10 30) ]

Edit: Here’s something a little less trivial: a recursive drawing of a Koch snowflake.

import Graphics.Gloss picture = kochSnowflake 4 kochSnowflake n = pictures [ rotate 0 (translate 0 (-sqrt 3 * 100 / 6) (kochLine 100 n)), rotate 120 (translate 0 (-sqrt 3 * 100 / 6) (kochLine 100 n)), rotate 240 (translate 0 (-sqrt 3 * 100 / 6) (kochLine 100 n)) ] kochLine k 0 = line [(-k/2, 0), (k/2, 0) ] kochLine k n = pictures [ translate ( k/3) 0 (kochLine (k/3) (n-1)), translate (-k/3) 0 (kochLine (k/3) (n-1)), translate (-k/12) (-sqrt 3 * k/12) (rotate 300 (kochLine (k/3) (n-1))), translate ( k/12) (-sqrt 3 * k/12) (rotate 60 (kochLine (k/3) (n-1))) ]

You can find complete documentation for the gloss package, of course, at http://hackage.haskell.org/package/gloss. Note that the server currently only implements the equivalent of displayInWindow, and rather than using the I/O action (which you can’t do, since SafeHaskell won’t let you do anything but purely functional code), you just define a top-level symbol called “picture” in your module.

Thoughts on SafeHaskell

Overall, I’m thrilled to have the SafeHaskell stuff in GHC. It just has so many potential uses… it’s Java-style sandboxing, but at compile time!

There is one thing that confuses me, though… in order to get this working, I had to patch the gloss library to add “Trustworthy” declarations. This is not ideal, for two reasons:

There are plenty of Haskell modules out there that GHC could easily prove are safe: if nothing else, just try to build them with the Safe extension, and if it fails, try again without it. The vast, vast majority of Haskell packages would pass this test, and become available for use in safe code. But that doesn’t seem to be what happens. A module isn’t considered safe unless it’s explicitly specified to be safe, at compile time. That greatly reduces the amount of code it’s possible to use from safe code, and sets up a huge obstacle in the way of getting a usable safe code ecosystem.

Even worse, in order to make this feasible at all, I had to declare gloss not just safe, but trustworthy. I really shouldn’t have done that, since I haven’t vetted all of the gloss code to ensure that it doesn’t let you do bad stuff. I really wanted GHC to assume that proof obligation, but instead I did myself. Why? Well, if I’d made it safe, I would have had to declare this for only certain modules (a much more intrusive change) and transitively go modify and rebuild all the pure code that gloss depends on, and so on down the dependency tree.

Perhaps I missed something, but if GHC is missing the opportunity to decide for itself when a module is safe, that’s a real shame, and something that will stand as an obstacle in the way of plenty of much more interesting and grander uses of SafeHaskell.

Anyway, that’s it for now! Have fun playing…