Haskell is a purely functional programming language.

In purely functional languages, a function has no side effects. The only thing a function can do is calculate something and return it as a result.

If a function is called twice with the same parameters, it’s guaranteed to return the same result. That’s called referential transparency.

Haskell is lazy. That means that unless specifically told otherwise, Haskell won’t execute functions and calculate things until it’s really forced to show you a result.

Haskell is statically typed. Haskell uses a very good type system and has type inference.

The two main Haskell compilers are GHC (Glasgow Haskell Compiler) and Hugs.

GHC can take a Haskell script (.hs extention usually) and compile it. But it also works in an interactive mode, where you can call functions from scripts that you load and the results are displayed immediately.

Interactive mode is invoked by typing ghci at your prompt.

If we have defined some functions in a file called file1.hs, we load up those functions by typing :l file1, and we can now play with them. If we change the .hs script, just run this command again or do :r, which reloads the current script.

Okay, we type ghci in the terminal. GHCi version blah blah, Loading package base .. linking .. done.
Prelude>

do :set prompt "ghci> "
Now, we can ghci> as the prompt.


Simple arithmetic,

ghci> 2 + 15
17

ghci> 49 * 100
4900

ghci> 1892 - 1472
420

ghci> 5 / 2
2.5

Several operators on one line and parentheses,

ghci> (50 * 100) - 4999
1

ghci> 50 * 100 - 4999
1

ghci> 50 * (100 - 4999)
-244950

With negative numbers, use parentheses,

5 * (-3) is cool but not 5 * -3

Boolean algebra,

ghci> True && False
False

ghci> True || False
True

ghci> not False
True

ghci> not (True && True)
False

Testing for equality,

ghci> 1 == 0
False

ghci> 5 /= 5
False

ghci> 5 /= 4
True

ghci> "hello" == "hello"
True

5 + “4” gives error. + expects its left and right side to be numbers.

We can do 5 + 4.0, and 5 will adapt.

True == 5 gives that types do not match. == works on any two things that can be compared, but it has to be two things of the same type.


We’ve been using functions here. + is a function. But it’s an infix function. Most functions that aren’t used with numbers are prefix.

ghci> succ 8
9

The succ function takes anything that has a defined successor and returns that successor.

In Haskell, functions are called by writing the function name, a space, and then the parameters, separated by spaces.

Calling a function with several parameters,

ghci> min 9 10
9

ghci> max 3.4 3.2
3.4

Function application (calling a function by putting a space after it and then typing out the parameters) has the highest precedence,

ghci> succ 9 * 10
100

ghci> succ (9 * 10)
91

ghci> succ 9 + max 5 4 + 1
16

If a function takes two parameters, we can also call it as an infix function by surrounding it with backticks — makes for better reading,

ghci> div 92 10
9

ghci> 92 `div` 10
9

So, bar (bar 3) in Haskell means bar is called with parameter 3, and then outer bar is called with this result. It’s not like function calling in imperative languages.


Functions are defined in a similar way that they are called. The function name is followed by parameters separated by spaces. But when defining functions, there’s a = and after that we define what the function does,

doubleMe x = x + x

Save the above as baby.hs, and load ghci in that directory, then

ghci> :l baby 
[1 of 1] Compiling Main ( baby.hs , interpreted ) 
Ok, modules loaded: Main. 

ghci> doubleMe 9 
18 

ghci> doubleMe 8.3 
16.6

Defining another function in baby.hs,

doubleUs x y = x*2 + y*2

Now we do,

ghci> doubleUs 28 88 + doubleMe 123 
478

We can call our own functions from our own functions. We could have defined, for instance,

doubleUs x y = doubleMe x + doubleMe y

Functions in Haskell don’t have to be in any particular order, so it doesn’t matter if you define doubleMe first and then doubleUs or if you do it the other way around.

A function that multiplies a number by 2 but only if that number is to 100,

doubleSmallNumber x = if x > 100 
						then x 
						else x*2

In the if statement in Haskell, else part is mandatory. In imperative languages you can just skip a couple of steps if the condition isn’t satisfied but in Haskell every expression and function must return something.

Because the else is mandatory, an if statement will always return something and that’s why it’s an expression.

doubleSmallNumber x = ( if x > 100 then x else x*2) + 1

It’s valid syntax to use ' in a function name. Usually used to either denote a strict version of a function (one that isn’t lazy) or a slightly modified version of a function or a variable.

Functions can’t begin with uppercase letters.
When a function doesn’t take any parameters, we usually say it’s a definition (or a name).


In Haskell, lists are a homogenous data structure. It stores several elements of the same type.

ghci> let lostNumbers = [4,8,15,16,23,48] 

ghci> lostNumbers 
[4,8,15,16,23,48]

Note: We can use the let keyword to define a name right in GHCI. Doing let a = 1 inside GHCI is the equivalent of writing a = 1 in a script and then loading it.

Strings are just lists of characters. "hello" is just syntactic sugar for [’h’,’e’,’l’,’l’,’o’]. Because strings are lists, we can use list functions on them, which is really handy.

Putting two lists together with ++ operator,

ghci> [1,2,3,4] ++ [9,10,11,12] 
[1,2,3,4,9,10,11,12] 

ghci> "hello" ++ " " ++ "world" 
"hello world" 

ghci> [’w’,’o’] ++ [’o’,’t’] 
"woot"

When we do [1,2,3] ++ [4], Haskell has to walk through the whole list on the left side of ++. So, keep in mind when dealing with huge lists. However, putting something at the beginning of a list using the : (cons) operator, is instantaneous.

ghci> 'A':" Small Cat"
A Small Cat

ghci> 5:[1,2,3,4,5]
[5,1,2,3,4,5]

So, : takes a number for a list of numbers, a character for a list of characters. Whereas, ++ takes two lists.

[1,2,3] is just syntactic sugar for 1:2:3:[]. [] is an empty list.

[], [[]], [[],[],[]] is an empty list, a list that contains an empty list, and a list that contains three empty lists, respectively.

To get an element out of a list by index, use !!,

ghci> [9.4,33.2,96.2,23.25] !! 1
33.2

The lists within a list can be of different lengths, but not of different types. Just like you can’t have a list that has some characters and some numbers, you can’t have a list that contains some lists of characters and some lists of numbers.

Lists can compared if the stuff they contain can be compared. When using >, >=, < and <=! to compare lists, they are compared in lexicographical order. First the heads are compared, if they are equal, the second elements are compared etc.

ghci> [3,2,1] > [2,1,0]
True

ghci> [3,2,1] > [2,10,100]
True

ghci> [3,4,2] > [3,4]
True

ghci> [3,4,2] == [3,4,2]
True

head takes a list and returns its head. The head of a list is basically it’s first element,

ghci> head [5,4,3,2,1]
5

tail takes a list and returns its tail. It basically chops off a list’s head,

ghci> tail [5,4,3,2,1]
[4,3,2,1]

last takes a list and returns its last element,

ghci> last [5,4,3,2,1]
1

init takes a list and returns everything except its last element,

ghci> init [5,4,3,2,1]
[5,4,3,2]

Be careful not to use head, tail, last or init on empty lists.