Skip main navigation

Keep Your Programs Tidy

How do we structure Haskell programs, particularly as they get larger and more complex? In this article, Dr Jeremy Singer outlines scoping constructs.
Wall painting about Software Development
© University of Glasgow

Scoping is an important way to keep your programs tidy. It involves limiting the region of the program in which names ‘exist’ and can be used.

In Haskell, a let expression provides local scope.
A let expression has a series of equations defining
variable values and a final expression
(after the in keyword) that computes a value
with those variables in scope.

Here is an example:

let x = 2
in x*x

What will this expression evaluate to?

Multiple variables can be defined in a single let

let x = 2
y = 3
in x+y

What will this expression evaluate to?

Note that the variable names line up
underneath one another
This is good formatting practice, but is also needed
for Haskell to interpret the code correctly.
Like Python, whitespace is important in Haskell,
certainly in let expressions anyway!

Sometimes in a let, one of the variables might
depend on another — in the function below, gallons depends on
milespergallon:

journeycost :: Float -> Float -> Float
journeycost miles fuelcostperlitre =
let milespergallon = 35
litrespergallon = 4.55
gallons = miles/milespergallon
in (gallons*litrespergallon*fuelcostperlitre)

Here’s a geometric example:

let diameter = 2*radius
circumference = pi*diameter
in (diameter, circumference)

By the way, pi is a defined constant in the Haskell Prelude.

Where clauses

There is another syntax for introducing local variables, called
the where clause.
As we have seen, Haskell is the Swiss army knife of programming languages: there are lots of ways of doing things.

The where keyword, inside an equation, provides
definitions for variables that are used in the equation.

Here are a couple of examples

squareplusone :: Int -> Int
squareplusone x = xsquared + 1
where xsquared = x*x

Note that where must be indented more than the start of the
enclosing equation.

Like let, we can have multiple variables inside a where
clause. Look at this temperature conversion function:

cel2fahr :: Float -> Float
cel2fahr x = (x*scalingfactor) + freezingpoint
where scalingfactor = 9.0/5.0
freezingpoint = 32

Again, notice that the variables defined in the where clause all
line up underneath each other.

You might think let and where are very similar!

  • Both introduce a local scope.
  • Both allow any number of equations to be written.
  • Both allow the equations to be written in any order, and variables defined in any equation can be used (“are in scope”) in the other equations.

However there are some important differences:

  • let expressions are expressions; let can be used anywhere an expression is allowed.
  • where clauses are not expressions; they can be used only to provide some local variables for a top level equation.

In which circumstances do you think it might it be better to use let instead of where? Or the other way round? Please write suggestions in the comments below.

© University of Glasgow
This article is from the free online

Functional Programming in Haskell: Supercharge Your Coding

Created by
FutureLearn - Learning For Life

Our purpose is to transform access to education.

We offer a diverse selection of courses from leading universities and cultural institutions from around the world. These are delivered one step at a time, and are accessible on mobile, tablet and desktop, so you can fit learning around your life.

We believe learning should be an enjoyable, social experience, so our courses offer the opportunity to discuss what you’re learning with others as you go, helping you make fresh discoveries and form new ideas.
You can unlock new opportunities with unlimited access to hundreds of online short courses for a year by subscribing to our Unlimited package. Build your knowledge with top universities and organisations.

Learn more about how FutureLearn is transforming access to education