Notes on Haskell
Tags: tech, technical, haskell
Published: 2021-11-02 20:34:54

---
title: Notes on Haskell
published: true
date: 2018-09-14 14:07:00 UTC
tags: Tech,Technical,Haskell
canonical_url: https://yosuf.dev/notes-on-haskell/
---

_These are notes from my lectures at university augmented with some online and textbook reading. They’re unfinished but they’ve been sitting in my drafts so I thought I’d publish them in case others find them useful._

> _Surely there must be a less primitive way of making big changes in the store than by pushing vast numbers of words back and forth through the von Neumann bottleneck. Not only is this tube a literal bottleneck for the data traffic of a problem, but, more importantly, it is an intellectual bottleneck that has kept us tied to word-at-a-time thinking instead of encouraging us to think in terms of the larger conceptual units of the task at hand. Thus programming is basically planning and detailing the enormous traffic of words through the von Neumann bottleneck, and much of that traffic concerns not significant data itself, but where to find it. — John Backus_

# **Contents**

- Thinking functionally
- GHCi
- Basics
- Lists
- Expressions and Types
- Functions
- Constrained Polymorphism
- Language Details

# **Thinking Functionally**

Procedural programming closely mirrors the underlying architecture and focuses on _how_ something is done. Declarative programming (including functional) focuses on _what_ the answer is and provides powerful abstraction (generalisation) mechanisms, as well as being concise and expressive.

Functional programming is programming with functions (lol). The most basic component is a function. They determine a unique output for each combination of inputs.

Instead of asking “How do I change the value of a variable?” or “How do I write a loop?”, ask “What value do I want to produce?”, “How can I make it from the input?” “What are the intermediate values?”.

Expressions are just their values and should be interchangeable.

**GHCi**

GHC is the compiler for Haskell. GHCi is the interactive environment in which Haskell expressions can be interactively evaluated and programs can be interpreted. It’s what you use on the command line to write Haskell. If you want to follow along, you can either download GHCi or use [repl.it](http://repl.it/languages/haskell) for a browser-based environment.

Prelude is just what you get for the command prompt when inside GHCi:

```
Prelude>
```

**GHCi Commands**

```
:load filename … (or :l as a shortcut) — loads modules from specified 
files:reload (or :r) - repeats the last load command
:type exp (or :t) - prints the type of the expression
:quit (or :q) - exits the interpreter
```

# **Basics**

Examples of basic math operations as well as using built-in functions:

```
Prelude> 2+3
5

Prelude> 2+3*5
17

Prelude> (2+3)*5
25

Prelude> 2^3
8

Prelude> sqrt 2
1.4142135623730951

Prelude> sqrt 2 + 3
4.414213562373095

Prelude> sqrt (sqrt 2)
1.189207115002721

Prelude> max 4 8
8

Prelude> div 13 5
2

Prelude> mod 13 5
3

Prelude> 13 `div` 5
2

Prelude> 13 `mod` 5
3
```

The last two are examples of infix functions (take note of the weird quotes).

# **Lists**

```
Prelude> [1, 1+3, 1+3+5]
[1,4,9]
```

The value of [a..b] is a list of integers starting at **a** and ending at **b**.

```
Prelude> [1..6]
[1,2,3,4,5,6]

Prelude> [2..2]
[2]

Prelude> [6..1]
[]

Prelude> [6,5..1]
[6,5,4,3,2,1]

Prelude> 1:2:[]
[1,2]
```

Some list related functions:

```
Prelude> product [3,4,5]
60

Prelude> product [1..7]
5040

Prelude> product []
1

Prelude> length [1,3,5]
3

Prelude> reverse [1,3,5]
[5,3,1]
```

If you’re wondering why **product [] = 1**, its because of the [identity in the category of multiplication](https://stackoverflow.com/questions/33732513/why-does-product-return-1). A practical explanation:

```
product [1,2,3]
	== product [1] * product 2:3:[]
	== product [1] * product [2] * product 3:[]
	== product [1] * product [2] * product [3] * product []
```

which allows us to implement it with simple recursion:

```
product [] = 1
product (x:xs) = x * product xs
```

In Haskell, strings are just lists of characters:

```
Prelude> ['H', 'e', 'l', 'l', 'o']
"Hello"

Prelude> ['a'..'z']
"abcdefghijklmnopqrstuvwxyz"

Prelude> length "Hello"
5

Prelude> reverse "Hello"
"olleH"
```

**[char]** is synonymous with **String**.

# **Expressions and Types**

![](https://miro.medium.com/max/1400/1*2LJzBg86pHVL9UWRda-szQ.png)
_Basic Types in Haskell_

**Types**

Every expression in Haskell has a type.

Unlike some languages like Java and Pascal, Haskell has type inference. If we write a number we don’t have to tell Haskell it’s a number. It can _infer_ that on its own, so we don’t have to explicitly write out the types of our functions and expressions to get things done.

**Types** are sets of values, and **Typeclasses** are sets of Types.

For example, the type _Integer_ includes values like 3 and 8, and the Typeclass _Num_ includes the Types Integer and Double.

This is somewhat analogous to Java, where Classes are sets of Objects, and Interfaces are sets of Classes:

![](https://yosuf.dev/content/images/2021/07/image.png)

Checking the type of 3 gives us a weird answer:

```
Prelude> :t 3
3 :: Num a => a
```

Here, **a** is called a type variable. Everything before the **=>** is called the class constraint. The above says “_there is some type_ **_a_** _in the typeclass_ **_Num_** _, 3 is of type_ **_a_**.” The value of 3 belongs to every type in the Num typeclass, including Integer and Double. Haskell is just being lazy and not committing to a specific type.

Functions also have types:

```
Prelude> :t head
head :: [a] -> a
```

This says for any type **a** , the function _head_ takes a list of **a** s and returns an **a**. (head returns the first element of a list).

We can even ask for the type of a plus operator. We surround it with parentheses since its an infix operator (meaning we usually use it between values: 2 + 2, otherwise GHCi will get confused and think we’re actually using it ):

```
Prelude> :t (+)
(+) :: Num a => a -> a -> a
```

This says: “There is some type **a** in the typeclass **Num** , “+” takes two **a** s and returns another **a**.

How about the function zip:

```
Prelude> :t zip
zip :: [a] -> [b] -> [(a, b)]
```

Zip takes a list of **a** s and a list of **b** s and it returns a list of **(a,b)** pairs.

We’re allowed to specify the type of a function along with its definition, which is generally considered good practice:

```
add :: Integer -> Integer -> Integer
add x y = x + y
```

On the first line, we explicitly tell Haskell that the add function we’re about to define takes two Integers and returns an Integer. Then we define the function on the second line.

Being explicit about types provides some documentation for us and anyone who reads our code, but it also helps us find bugs. For example, say we have the following function:

```
dividesEvenly x y = (y / x) * x == y
```

This function is meant to tell us if x evenly divides into y. So if x=2, and y=5, we would expect (5/2) to be 2, since 2 goes into 5 twice, then 2\*2 would give us 4. 4==5 is not true so we would expect this function to return False given 2 5 as arguments. However, it returns True.

```
Prelude> dividesEvenly 2 5
True
```

This is because, in Haskell, 5/2 is not 2, but 2.5. One way to address this is to specify that we expect x and y to be Ints:

```
Prelude> dividesEvenly :: Int -> Int -> Bool
Prelude> dividesEvenly x y = (y / x) * x == y
```

However, this gives us an error:

```
<interactive>:3:1: error:    
	• No instance for (Fractional Int)
	    	arising from a use of ‘dividesEvenly’
```

It is telling us that Int is not a member of the typeclass Fractional. The **/** operator only works on Fractionals. Turns out the operator we want is **`div`** :

```
Prelude> dividesEvenly :: Int -> Int -> Bool
Prelude> dividesEvenly x y = (y `div` x) * x == y
Prelude> divideEvenly 2 5 False
```

By specifying the type of our function, we were able to find a bug that we may have otherwise missed.

# Functions

**Infix Operators**

Haskell permits the usual infix notation:

```
Prelude> 1 + 2*3
11
```

The infix operators `+` and `*` refer to functions that take two arguments. Operators also have precedence and associations. To refer to these kinds of functions by themselves, we wrap them in parentheses, writing `(+)` and `(*)`. So we can use them like this:

```
Prelude> (*) 2 5
10
Prelude> (+) 1 ((*) 2 5)
11
```

If we have ordinary identifiers that refer to binary functions:

```
div :: Int -> Int -> Int
mod :: Int -> Int -> Int
```

we can use them as infix functions by wrapping them in backquotes:

```
Prelude> (1987 `div` 100) `mod` 4
```

which is the same as:

```
Prelude> mod (div 1987 100) 4
```

**Functions on Int**

```
(+) :: Int -> Int -> Int
(-) :: Int -> Int -> Int
(*) :: Int -> Int -> Int
(^) :: Int -> Int -> Int
div :: Int -> Int -> Int
mod :: Int -> Int -> Int
abs :: Int -> Int
negate :: Int -> Int
```

Examples:

```
Prelude> abs 3
3

Prelude> negate 3
-3

Prelude> abs (negate 3)
3

Prelude> negate (negate 3)
3

Prelude> abs 0
0

Prelude> negate 0
0
```

**Relational Operators**

```
(<) :: Int -> Int -> Bool
(<=) :: Int -> Int -> Bool
(>) :: Int -> Int -> Bool
(>=) :: Int -> Int -> Bool
(==) :: Int -> Int -> Bool
(/=) :: Int -> Int -> Bool
```

Examples:

```
Prelude> 2 < 3
True

Prelude> 2 < 3
True

Prelude> 2 < 2
False
Prelude> 2 /= 2
False

Prelude> 2 /= 3
True
```

**Overloading**

The `(==)` function has several types:

```
(==) :: Int -> Int -> Bool
(==) :: Bool -> Bool -> Bool
(==) :: Char -> Char -> Bool
(==) :: Float -> Float -> Bool
(==) :: Eq a => a -> a -> Bool
(<=) :: Ord a => a -> a -> Bool
```

**Building Boolean expressions**

```
(&&) :: Bool -> Bool -> Bool
(||) :: Bool -> Bool -> Bool
not :: Bool -> Bool
```

Examples:

```
Prelude> not True
False

Prelude> False || True
True

Prelude> 1 < 2 || 1 > 2
True
```

A function using relational operators:

```
small :: Int -> Bool
small n = 0 <= n && n < 10
```

**Functions between types**

Haskell has no implicit conversion between types. You must use explicit functions:

![](https://yosuf.dev/content/images/2021/07/image-1.png)

To use the `ord` and `chr` functions, you must import the `Data.Char` library module:

```
Prelude> floor 3.7
3

Prelude> ceiling 3.7
4

Prelude> :m + Data.Char

Prelude> ord 'a'
97

Prelude> chr 98
'b'
```

**Functions of Char**

```
isDigit :: Char -> Bool
isDigit c = ’0’ <= c && c <= ’9’
isUpper, isLower :: Char -> Bool
isUpper c = ’A’ <= c && c <= ’Z’
isLower c = ’a’ <= c && c <= ’z’
isAlpha :: Char -> Bool
isAlpha c = isUpper c || isLower c
ord :: Char -> Int
chr :: Int -> Char
```

Examples:

```
Prelude> :m + Data.Char

Prelude> isDigit '2'
True

Prelude> isLower 'B'
False

Prelude> ord '1'
49

Prelude> chr 65
'A'

Prelude> chr 48
'0'

Prelude> chr 32
' '

Prelude> chr (ord 'b')
'b'

Prelude> chr (ord 'b' + 3)
'e'
```

**Functions on Float**

```
(+) :: Float -> Float -> Float
(-) :: Float -> Float -> Float
(*) :: Float -> Float -> Float
(/) :: Float -> Float -> Float
(^) :: Float -> Int -> Float
abs :: Float -> Float
negate :: Float -> Float
sin :: Float -> Float
asin :: Float -> Float
exp :: Float -> Float
log :: Float -> Float
sqrt :: Float -> Float
```

**Guarded Definitions**

```
maxTwo :: Int -> Int -> Int
maxTwo x y
	| x >= y = x
	| otherwise = y
```

The Boolean expression `x >= y` is called a guard. Guards are tested in order, so if we had:

```
maxThree :: Int -> Int -> Int -> Int
maxThree x y z
	| x >= y && x >= z = x
	| y >= x && y >= z = y
	| otherwise = z
```

it could be simplified to:

```
maxThree :: Int -> Int -> Int -> Int
maxThree x y z
	| x >= y && x >= z = x
	| y >= z = y
	| otherwise = z
```

**Conditional Expressions**

Haskell also has an expression form: `if boolexp then exp1 esle exp2` _._

So instead of:

```
maxTwo :: Int -> Int -> Int
maxTwo x y
	| x >= y = x
	| otherwise = y
```

we could write:

```
max :: Int -> Int -> Int
max x y = if x >= y then x else y
```

You can also define functions using existing functions. So you could turn this:

```
maxThree :: Int -> Int -> Int -> Int
maxThree x y z
	| x >= y && x >= z = x
	| y >= z = y
	| otherwise = z
```

into this:

```
maxThree x y z = maxTwo x (maxTwo y z)
```

**Local Definitions**

You can have local definitions which are further indented and must line up:

```
sumSquares :: Int -> Int -> Int
sumSquares n m
	= sqN + sqM
		where
		sqN = n*n
		sqM = m*m
```

You can use local definitions in all guards, as well as the right-hand expressions:

```
maxsq :: Int -> Int -> Int
maxsq x y
	| sqx > sqy = sqx
	| otherwise = sqy
	where
	sqx = sq x
	sqy = sq y
    
	sq :: Int -> Int
	sq z = z*z
```

# **Constrained polymorphism**

For example, the “element” function takes two arguments and asks “does the first argument occur in the second argument (which is a structure of some kind)? And it works for multiple types:

```
Prelude> elem ‘e’ “Hello”
True

Prelude> elem 3 [1..5]
True
```

This function is almost polymorphic: the types of things being compared must support _equality testing_, which is reflected in the constrained type of elem:

```
Prelude> :t elem
elem :: (Eq a, Foldable t) => a -> t a -> Bool
```

Here, **Eq a** is a constraint on the type of **a**. The type **a** must belong to the typeclass **Eq** : those that support equality testing such as Char, Int and Integer.

# **Language Details**

**Indentation**

In files, Haskell uses indentation to decide where another definition starts, so all definitions must have the same indentation. The following would be seen as two definitions and is legal:

```
square
	:: Integer -> Integer
square n = n * n	
```

The following are not legal, Haskell sees the first as one definition and the second as two definitions:

```
square :: Integer -> Integer
	square n = n * n

square
:: Integer -> Integer
```

* * *

> Subscribe to my [Substack](https://yosuf.substack.com/subscribe) to be notified of future posts.