On CodeWorld and Haskell

I’ve been pouring a lot of effort into CodeWorld lately… and I wanted to write a sort of apology to the Haskell community. Well, perhaps not an apology, because I believe I did the right thing. But at the same time, I realize that decisions I’ve made haven’t been entirely popular among Haskell programmers. I’d like to explain what happened, and try to make it up to you!

What Happened

Originally, I started this project using Haskell and the excellent gloss package, by Ben Lippmeier. CodeWorld has been moving slowly further and further away from the rest of the Haskell community. This has happened in a sequence of steps:

Why It Happened?

First, I want to point out some things that are not the reason for any of this:

I did not do this because I think there’s something wrong with Haskell. I love type classes. I love currying, and especially love how it’s not just a convenient trick, but sometimes introduces whole new perspectives by viewing tedious functions of multiple parameters as simple, clean, and elegant higher-order functions.

I also did not do this because I think anyone is incapable of learning full-fledged Haskell. In fact, I taught full-fledged Haskell to middle schoolers for a year. I know they can do it.

So why did I do it? Two reasons:

Teaching mathematics has always been more important to me than teaching Haskell. While Haskell is an awesome programming language, mathematics is just an awesome perspective on life. For every student who benefits from learning an inspiring programming language, many students will benefit from learning that humanity has a method called mathematics for thinking about fundamental truths in a systematic, logical way that can capture things precisely. So any time I have to choose between pushing students further toward their math education or away from it, I’ll choose toward it.

Details matter. Even though I know kids are capable of a lot, they are capable of a lot more without artificial obstacles in their way. I learned this the hard way teaching this class the first time. The smallest little things, with absolutely no great significance as a language, matter a lot. Having to put parentheses around negative numbers obscures students from reaching leaps of understanding. Confusing error messages mean the difference between a student who spends a weekend learning, and one who gives up on Friday afternoon and doesn’t think about it until the next school day. Different surface syntax means that a lot of kids never fully make the connection that functions here are the same thing as functions there.

In the end, I do think these were the right decisions… despite the frustration they can cause for Haskell programmers who know there’s a better way.

Making Up For It

A couple weekends ago, though, I worked on something to hopefully restore some of this loss for Haskellers. You see, all the changes I’ve made, in the end, come from replacing the Prelude module with my own alternative. Specifically:

I deliberately replaced functions from the Prelude with my modified versions. Because I provided an alternative Prelude, I had to hide the base package, which made it impossible to import things like Control.Monad. This was not a deliberate decision. It just happened.

So I fixed this. I added to the codeworld-base package re-exports of all of the modules from base. I renamed Prelude to HaskellPrelude in the process, so that it doesn’t conflict with my own Prelude. And finally, I added a new module, CodeWorld, that exports all the really new stuff from CodeWorld like pictures, colors, and the interpreters for pictures, animations, simulations, etc. The result is that you can now start your programs with the following:

import Prelude()

import HaskellPrelude

import CodeWorld -- If you still want to do pictures, etc.



main = putStrLn "Hello, World"

At this point, you can write any Haskell you like! You aren’t even constrained to pure code, or safe code. (The exception: TemplateHaskell is still rejected, since the compiler runs on the server, so TH code would execute code on the server.)

In fact, it’s even better! You’re free to use GHCJS JavaScript foreign imports, to interact with the browser environment! See a brief example here. Now you’re out of the sandbox, and are free to play around however you like.

Right now, the CodeWorld module still uses uncurried functions and other CodeWorld conventions like Number for numbers, etc. There’s no reason for this, and it’s something that I should probably change. Anyone want to send a pull request?