1.2 Creating your own functions

You are not limited to the functions that Haskell provides. You can also create your own functions using the lambda notation.

> (\ a -> a + 1) 2
3
> (\ a b -> a + b) 3 4
7

Lambda notation has the form \ inputs -> expression. The backslash represents the greek letter lambda (λ), which comes from its use in mathematics to represent functions. Then the inputs follow, each given a name and separated by blank spaces. This is followed by an arrow ->, and then finally the expression that calculates the output for the function. You can think of the inputs as slots that are waiting to be filled with values so that the expression on the right-hand side of the arrow can be computed. Let’s look at the first lambda expression from above to understand how it works.

\ a -> a + 1

This function has only one input. When we apply this function to a number, that number fills the first (and only) input slot, and is assigned the name “a”. Now that the number has a name, it can be used in the expression on the right-hand side of the arrow to compute the output. Since there are no more input slots to fill, this entire lambda expression is reduced to just its output expression. All of the variables (in this case, just “a”) are then substituted by their actual values, and the final result is computed. Below is an outline of the steps for reasoning about how lambda expressions work.

-- the function is applied to some value
(\ a -> a + 1) 2

-- assign variable names and reduce the expression
(a + 1), where a = 2

-- substitute variables
2 + 1

-- compute the result
3

If we look at the second lambda expression from earlier, we can see it behaves in a similar way, except there are two inputs instead of one.

-- the function is applied to some value(s)
(\ a b -> a + b) 3 4

-- assign variable names and reduce the expression
(a + b), where a = 3, b = 4

-- substitute variables
3 + 4

-- compute the result
7

Lambda expressions (known in math as lambda abstractions) are a basic building block of Haskell programs. Try the following exercises before moving on.

Exercise 1

Write a lambda expression that computes the square of a number (the number multiplied by itself)

Solution

There are at least two good ways to define this function. The first involves a simple multiplication.

> (\ x -> x * x) 3
9

The second way uses a power function ** provided by Haskell. It multiplies the left-hand input by itself a number of times equal to the right-hand input. In the following lambda expression, the variable x is multiplied by itself twice.

> (\ x -> x ** 2) 3
9
Exercise 2

Write a lambda expression that computes the cube root of a number. (Hint: use the power function **)

Solution

Lucky for us, the power function ** accepts fractional numbers (as opposed to only accepting whole numbers), so we can use 1/3 as the exponent.

> (\ x -> x ** (1 / 3)) 8
2.0
Exercise 3

Write a lambda expression that computes the circumference of a circle given the radius using the formula 2π * radius. (Hint: Haskell already has a definition for π called pi.

Solution

Since Haskell already defines pi,

> pi
3.141592653589793

let’s use that in our calculation.

> (\ radius -> 2 * pi * radius) 3
18.84955592153876

There is a special feature in ghci that allows us to temporarily give names to expressions, including lambda expressions.

> square = \ x -> x * x
> square 3
9

And you can even overwrite previous definitions, if you wish.

> square = \x -> 4
> square 3
4

Now our square function is obviously incorrect, because it will always return the number 4, but you can see that the previous definition has been overwritten. Overwriting definitions is a special feature of ghci, and does not work in normal Haskell code. In normal Haskell code, you can define something only once.

At some point you will want to save all of your definitions to a file. Open your text editor and create a new file called Lambdas.hs and type the following definitions into it. Save it in your current directory.

add = \ a b -> a + b

square = \ x -> x * x

cuberoot = \ a -> a ** (1 / 3)

circumference = \ radius -> 2 * pi * radius

Now in ghci, load the file using the special :load command.

> :load Lambdas.hs
[1 of 1] Compiling Lambdas ( Lambdas.hs, interpreted )
Ok, one module loaded.

If you see output like in the example above, then you are ready to use your defined functions.

> add 3 4
7
> square 5
25

You can make changes to this file—perhaps adding new definitions—and reload the file in ghci using the :reload command.

> :reload
Ok, one module loaded.

By now, you should be comfortable writing and understanding lambda expressions. So it’s a good time to mention that there is an alternate way to write your named function definitions that is slightly easier to read. The following is a lambda expression that has been assigned to the name add.

add = \ a b -> a + b

This could be written instead using an alternate syntax that removes the explicit lambda character, and replaces the arrow with an equal sign.

add a b = a + b

This is the preferred way to write named functions, and is the form that will be used throughout this book. Note that this syntax is only valid for named functions. For un-named functions you still need to use a lambda expression.

Exercise 4

Open up your Lambdas.hs file and rewrite the definitions to use the alternate syntax discussed above.

Solution
add a b = a + b

square x = x * x

cuberoot a = a ** (1 / 3)

circumference radius = 2 * pi * radius