Everything you need to know to get started with Haskell

We take a look at one of the most popular functional languages out there, Haskell.

Published Date
05 - Jan - 2016
| Last Updated
06 - Jan - 2016

Haskell is the new kid on the block of programming languages. It too follows the computing paradigm called ‘Functional Programming’ i.e. approach a problem in terms of what the solution should look like, rather than what steps should be taken to get to that solution.

Though Haskell has risen in popularity in recent years, the language itself is more than 20 years old. As far back as 1987, there existed at least a dozen implementations of a purely functional language, and at the conference of Functional Programming Languages and Computer Architecture (FPLCA) in Portland, it was decided to publish an open standard for functional programming to promote it as an alternative style of programming.

What is Functional Programming?

One example that’s oft cited is that of formulas in Microsoft Excel. When entering formulas in a cell, the final value is always expressed in terms of the values of other existing cells. No attempt is made to specify the order of evaluating these cells; instead, we expect that Excel will figure out dependencies on its own. Similarly, no attempt is made at managing the memory used by the expression. Finally, we program using expressions rather than instructions - an expression merely establishes the relationship between the inputs and the outputs without explicitly listing the steps required to fulfil that relationship.

As the name suggests, functions in a Functional Programming language (including Haskell) are first class citizens. This means that they can not only be invoked and called like their imperative counterparts, but also that functions can be passed as arguments to other functions, and can even be defined within the scope of other (parent) functions. This feature allows nearly all programming constructs to be expressed in the form of functions. A hallmark feature of all functional programming languages is that they are said to be ‘lazy’. So it only evaluates an expression when it is required, and not before. This is highly advantageous, especially when dealing with compound expressions (expressions where the operands themselves are expressions) or with infinitely large data structures such as infinite lists. Hence, these languages are far more memory efficient that their ‘strict evaluation’ counterparts. Furthermore, lazy evaluation reduced the number of computations by storing the result of all function calls against their parameters in the form of a lookup table which is used the next time the same function is called without bothering to re-compute it.

Take the example of computing the entire Fibonacci sequence. In Haskell, the sequence can be computed using the following one-liner:
fibs = 0 : 1 : zipWith (+) fibs (tail fibs)

Here, ‘fibs’ is the name of the list that will store the sequence, ‘0 : 1’ is the initialization of the list, and the ‘zipWith’ operator performs an operation (in this case, addition) on the corresponding elements of the two operators following it. The first operator is the list fibs itself, while the tail operator returns the list without the first element. Notice how no attempt is made to restrict the list. Since we haven’t actually tried to retrieve a value from this list, it will not be computed at all. If we were to call an element of the list (using fibs !! <element number n>), the list would then compute all elements upto and including the desired element, and return the nth element. Had the same logic been implemented in an eager or ‘strict’ language like as C or Java, it would’ve resulted in an infinite loop (or an exception, at best)

Put the following line in file called hello.hs and run it with ghc (included in the DVD)
main = putStrLn “Hello, World!”
Run it with the command ghc -o hello hello.hs

Defining functions in Haskell can be done in two ways, one where the single function takes multiple parameters (or arguments) and returns a value, and the other where a function acts on a single argument, which returns a function that will then take the second argument as its sole argument, and so on. The second approach is  a more ‘functional’ way to approach programming and the result is more compact than the former. This approach is called currying, named after the American mathematician Haskell Curry.
Here is an example to illustrate the difference in the two approaches - the following function ‘hyp’ computes the value of the hypotenuse of a right angled triangle given the lengths of the two shorter sides.

Currying :
hyp :: Float -> Float -> Float
hyp x y = sqrt (x*x + y*y)

Non-Currying:
hyp :: (Float, Float) -> Floathyp (x,y) = sqrt (x*x + y*y)

As can be seen, the first approach is more compact (uses fewer characters), and is hence used as per convention. Similarly, Haskell also supports anonymous or lambda functions using the ‘\’ operator.
List comprehensions are a way of synthesizing a list using an expression, where each element in the list is logically related to a parameter. For example, to make a list of all numbers from 1 to 100, the following Haskell one-liner is valid:
[ f | f <- [1..100]]
We can include powerful logic to modify our lists during runtime. For e.g., a list that contains the squares of all numbers present in a list l,
[f*f | f <- l]
Similarly, a list that stores all the factors of a number n can be expressed as,
[f | f <- [1..n], n mod f == 0]
(Here the mod operator returns the remainder after dividing n with f)

Monads are one of the most important features of Haskell, and can be thought of as the programmatic equivalent of an assembly line. Data that is input into a monad gets modified in stages as if it were to be on an assembly line. Formally, a monad is simply a way of describe any computation as a sequence of steps. Monads are used to define how a particular data type should behave when multiple operations on it are chained together, or how functions that are nested inside other functions should return values. Monads may be constructed for computations that handle I/O, change state of their resident variables or return multiple values.

The most commonly used (and full featured) Haskell compiler is the GHC (Glasgow Haskell Compiler) and is available for Windows, Mac and Linux (Check it here). Other implementations of Haskell such as lbc, Gofer and Yale Haskell are also available, but GHC is the de-facto standard for Haskell compilers. You can find the latest version of GHC on the DVD accompanying this month’s FastTrack issue. Text editors such as SublimeText, Vim, IntelliJ and Eclipse support Haskell.

A number of real world projects are written either partially or entirely in Haskell. Darcs is a source code management system that relies on a sophisticated system of diffs rather than snapshots and supports spontaneous branching. Large corporations such as Google, Facebook, NVIDIA, Bank of America and AT&T use Haskell internally for a number of support tools. Chordify is a popular chord transcribing service that takes a song from YouTube, Soundcloud or an uploaded audio file, and displays the chords used in the song. Haskell is used for modelling the musical harmony between chords in the functional domain.

The New York Times used Haskell’s parallel array library to process images from the 2013 New York Fashion Week. Silk a tool used to publish data visualizations in a beautiful way, uses Haskell to generate infographics from their data.