Haskell1 is a most unusual language. At one end it’s a hard-core functional language with impeccable CS credentials, but increasingly I’ve come to use it for simple mathematical calculations too.

I’m not entirely sure how the language manages to fill both roles so well, though it surely demonstrates the designers’ exquisitely good taste. However, I think the following are important:

Besides the language itself of course, it’s helpful to have some good libraries. Happily Hackage7 has lots of good stuff in it, though it can’t match e.g. the CPAN.8

A simple calculation

As an example, suppose we want to know the sum of the factorials of all the primes less than 50. Here’s one way (assuming you’ve installed the primes package9):

$ ghci
GHCi, version 7.4.2: http://www.haskell.org/ghc/  :? for help
Prelude> import Data.Numbers.Primes
Prelude Data.Numbers.Primes> let fac i = product [1..i]
Prelude Data.Numbers.Primes> sum [ fac i | i <- takeWhile (< 50) primes ]
258623301959883784393716899074939573050130131319471976510768

Note: I’ve removed some of ghci’s diagnostics to make things clearer.

Defining variables

Haskell can also play the poor man’s symbolic calculator, here calculating an approximate value of g, the acceleration due to gravity10 at the Earth’s surface:

$ ghci
GHCi, version 7.4.2: http://www.haskell.org/ghc/  :? for help
Prelude> let bigG = 6.674e-11
Prelude> let mE = 6e24
Prelude> let rE = 6.4e6
Prelude> bigG * mE / rE^2
9.776367187499998

Note: I’ve removed some of ghci’s diagnostics to make things clearer.

List Comprehensions

One of Haskell’s most succinct features is the list comprehension.11 Continuing from above let’s see how g changes as we ascend from the Earth:

Prelude> let g h = bigG * mE / (rE + h)^2
Prelude> [ (h, g h) | h <- [0,10000..100000] ]
[(0.0,9.776367187499998),(10000.0,9.745887495406212),...

That’s hardly the most readable of output, but Haskell has a printf clone12 which solves the problem:

Prelude> import Text.Printf
Prelude Text.Printf> hs = [0,10000..100000]
Prelude Text.Printf> putStr $ concat [ printf "%6.0f %.4f\n" h (g h) | h <- hs ]
     0 9.7764
 10000 9.7459
 20000 9.7156
 30000 9.6854
 40000 9.6553
 50000 9.6254
 60000 9.5956
 70000 9.5660
 80000 9.5365
 90000 9.5071
100000 9.4779

Of course you can do more than just a simple map. It’s easy to loop over more than one variable:

$ ghci
Prelude> import Data.Numbers.Primes
Prelude Data.Numbers.Primes> [ p^i | p <- take 5 primes, i <- [1..3] ]
[2,4,8,3,9,27,5,25,125,7,49,343,11,121,1331]

or define new variables:

... > [ (p,i,n) | p <- take 5 primes, i <- [1..3], let n = p^i ]
[(2,1,2),(2,2,4),(2,3,8),(3,1,3),(3,2,9),(3,3,27),(5,1,5),(5,2,25)...

or add conditions:

... > [ (p,i,n) | p <- take 5 primes, i <- [1..3], let n = p^i, n `mod` 10 == 7 ]
[(3,3,27),(7,1,7)]

Purity

Haskell is a pure13 language which means, amongst other things, that random bits of the program can’t simply do I/O.14

However, if you just want to write the results of a calculation to a file, it’s usually possible to ignore these issues, by replacing putStr with writeFile. One twist you’ll probably need is to convert the result of the calculation into a string first. Happily show does a passable job of that most of the time (and ghci uses it implicitly):

$ ghci
Prelude> import Data.Numbers.Primes
Prelude Data.Numbers.Primes> let ps = takeWhile (< 50) primes
Prelude Data.Numbers.Primes> ps
[2,3,5,7,11,13,17,19,23,29,31,37,41,43,47]
Prelude Data.Numbers.Primes> putStrLn $ show ps
[2,3,5,7,11,13,17,19,23,29,31,37,41,43,47]
Prelude Data.Numbers.Primes> writeFile "primes.txt" $ show ps
Prelude Data.Numbers.Primes> ^D
$ cat primes.txt
[2,3,5,7,11,13,17,19,23,29,31,37,41,43,47]

Source files

So far, all of these examples are just typed at the ghci prompt. In practice, for more complicated calculations, or those you want to keep, it’s helpful to save things in a Haskell file which you can then load into ghci.

I use this a lot for solving geocache15 puzzles. For example, there’s a cache in Paris where you have to identify the models of car16 and then do some simple arithmetic.

Here, in its entirety, is the trivial Haskell program I wrote as I solved it (with fake data):

a = 123
b = 123
c = 123
d = 123
e = 123
f = 123
g = 123
h = 123
i = 123
j = 123
k = 123
l = 123
m = 123
n = 123
o = 123
p = 123

xxxx = c + e + f + l + m + n + o - 96 - 52
yyyy = a + b + d + g + h + i + j + k + p + 3701 - 37

And here’s how I ran it:

$ ghci cars.hs
GHCi, version 7.4.2: http://www.haskell.org/ghc/  :? for help
... [1 of 1] Compiling Main             ( cars.hs, interpreted )
Ok, modules loaded: Main.
*Main> xxxx
9999
*Main> yyyy
9999

There’s nothing very sophisticated or elegant about it, but equally the source code is almost exactly what I’d write on paper were I to do it by hand.

However, unlike the paper version, it would be easy to extend this if I wasn’t sure of some of the values and wanted to calculate all the possible coordinates. If I felt particularly keen I could even write them to a file, perhaps in a format that e.g. Google Earth could understand.

Weaknesses

Text

Although it’s not always true, I still find Perl a better tool for quickly munging text. Perhaps it’s familiarity, or perhaps the seemless integration of regexps into the language remove just that bit of friction.

External data

One of the consequences of Haskell’s immutable data and purity is that it can be messy to work with e.g. a dictionary stored in a file. The contents of that file might change, so deep in the bowels of a library you can’t simply open it and read the contents, without jumping through a hoop or two.

For small–medium sized data sets, simply embedding the data in a Haskell source file seems a reasonable hack. Typically I’d write some trivial program to create that source file, which could then be included like any other library.