Ok, so here's what the program is going to do... On the picnicmob.org website, people answer a bunch of random questions. What we want our program to do is take a picture of a city park, a list of answers people gave on the questions, and have it figure out where people should sit in the park so that their neighbors are as similar as possible to them, based on similar answers for the questions. We're going to do this using a standard simulated annealing algorithm. (Read this for more info... we'll be describing the basics below, too...)
The only preparation you need to do for this tutorial is install the Glasgow Haskell Compiler- You can get the latest version from here. It's a very well supported and very fast compiler. We're just going to use the basic GHC libraries in this tutorial- No other installs are needed.
Now you have all you need to run the "Hello World" program below- Just copy the code into a file called tutorial.hs:
import Data.List import Text.Regex import System.Random import Data.Ord type Point = (Float,Float) type Color = (Int,Int,Int) type Polygon = [Point] type Person = [Int] type Link = [Point] type Placement = [(Point,Person)] type EnergyFunction a = a -> Int type TemperatureFunction = Int -> Int -> Float type TransitionProbabilityFunction = Int -> Int -> Float -> Float type MotionFunction a = StdGen -> a -> (StdGen,a) main = do putStr "Hello World! Let's have a picnic! \n"
After you've copied the code to a file, just run your new program from the command line as shown below:
> runHaskell tutorial.hs Hello World! Let's have a picnic!
*phew* That was easy!
As you can see, there's lots of stuff in this "Hello World" that doesn't seem necessary... Actually, only the last two lines (starting at main = do) are really needed to print our message... The rest is just header stuff that we'll use later in the tutorial...
At the top, you can see some things we're importing out of the standard GHC libraries:
The next few lines define different types that we're going to use in our picnic program... Haskell programmers are really fond of lots of types, because Haskell compilers are basically just these crazy type-crunching machines that will take any types you give them and if they find anything questionable about how you're using types they will let you know early, preventing your program from becoming buggy. The way Haskell compilers handle types puts them head and shoulders above most other compilers (Read more about Hindley-Milner type inference here.)
The lower type lines are a bit more difficult to understand- They describe the types of the four functions that are used in all simulated annealing algorithms... we'll be describing those later on. For now, just know that in Haskell you want to look at the last arrow, which looks like this ->... Anything to the left of that arrow is a parameter into our function- The thing to the right is the return value of the function. For instance, the EnergyFunction is a function that takes an arbitrary type a (which will be a seating arrangement of picnickers) and returns an integer, which is the "energy" of our picnic. A low energy will mean that all the picnickers are happy with where they're sitting. We'll explain these funcitons more later.
What's good is that in Haskell we can create all kinds of types to describe what we want to do and the Haskell compiler is very good at catching potential errors for us ahead of time. Defining types in Haskell is usually a choice and not a necessity- This program would run just fine, even if all the type declarations were missing... The Haskell compiler would just figure them out on its own!
Another thing that's good is that the part that writes "Hello World" is very short and simple in Haskell.
To keep things simple I'm building these new types using the type command, instead of another command called data. This other command (which you don't need to know about today) lets you attach a special new type name that you use to construct your new type- That name makes it even harder to accidentally use the wrong type in the wrong place in your program.
Another thing thats "bad" about this code is that we used the type Int. Unlike all other types in this program, Int has an upper limit and could theoretically cause our program to err out if any integers got way too massively big. In Haskell, this type of integer can't get bigger than 2^31... We could have used the type Integer instead- This type of integer grows "magically" and can hold any sized integer, no matter how big... but it's slower, so we used Int instead, since our numbers will never get that big.