Chapter 4


Tips ⚠️️

  • Use try.purescript.org to test out the code examples in this book.
  • Whenever the example code starts with module Main where, make sure to clear out the code editor on try.purescript.org before pasting new code in. This will help to avoid unncessary errors

Functions

Now that we have a basic understanding of creating and using variables, we can move on to the next primary tool in our toolbox: Functions. Functions are the cornerstone of programming, so we'll dedicate the next couple of sections to the understanding of this concept. Everything else we learn in the latter chapters of this book builds on top of this, so make sure to take your time here.

If you haven't programmed before, the extent of your experience with functions may be limited to that of high school algebra. First, you were taught the equation of a line, y = mx + b; then, without warning, the math teachers decided to get cute with us and rewrite it as f(x) = mx + b.

Functions in purescript are akin to those we learned in math, but I think you'll find that they are much more helpful than the functions you were taught in algebra.

The repetition problem

In order to really get a grasp of the utility functions provide, let's start off with a motivating example. Let's say your friend comes up to you one day and says

I've figured out how to determine if someone will have good luck or not! Here's how it works: First, have them pick a random number between 1 and 1000, then add 17 to their number, multiply by 13, subtract 9 and finally divide by 2! If their number is odd, then they will have good luck that day!

Obviously your friend is off his rocker, but suppose we wanted to create some people in a program and see if they have bad luck or not, how would we do that? Let's create 4 imaginary people and give them some lucky numbers!

Put the following example in your code editor:

module Main where
import Prelude

-- Darby picks 350 as his number
darby :: Int
darby = (((350 + 17) * 13) - 9) / 2

-- Pablo picks lucky number 17!
pablo :: Int
pablo = (((17 + 17) * 13) - 9) / 2

-- Jason picks 449
jason :: Int
jason = (((449 + 17) * 13) - 9) / 2

-- Dan picks 123
dan :: Int
dan = (((123 + 17) * 13) - 9) / 2

So you go and show your friend that you've tried out his formula in a purescript program, but regretfully, it turns out he got the formula wrong!

Sorry, instead of adding 17 to their number, we're actually supposed to add 13; and instead of dividing by 2 at the end, we're really supposed to divide by 4!

Great! Now we have to go and fix the formula in our program! Go ahead and adjust your formula in the code editor; when you're finished, you can check against the answer here to see that you're changes match.

Fixed lucky number formula
module Main where
import Prelude

-- Darby picks 350 as his number
darby :: Int
darby = (((350 + 13) * 13) - 9) / 4

-- Pablo picks lucky number 17!
pablo :: Int
pablo = (((17 + 13) * 13) - 9) / 4

-- Jason picks 449
jason :: Int
jason = (((449 + 13) * 13) - 9) / 4

-- Dan picks 123
dan :: Int
dan = (((123 + 13) * 13) - 9) / 4

It's quite annoying to have to run through every line fixing up the formula. Each line is also exactly the same besides the random number picked by each person. Imagine if we had picked numbers for 10 or 20 different people, the possibility that we might forget to fix some of the lines or make a typo becomes increasingly likely! And here's where functions come to the rescue...

Functions in action

When we talked about variables, we talked about instructing the computer to memorize data for us. Functions are similar, except instead of memorizing values, they memorize calculations. We can pack entire calculations into a variable-like name, and then invoke it on command by simply using the name again later on in the code.
We can write a function to encode the lucky number formula our eccentric friend described to us up above, it goes like this:

getLuckyNumber num =
  (((num + 17) * 13) - 9) / 2

We won't dive into the specifics of creating functions just yet, but let's compare this with the calculation of darby's lucky number:

-- Darby's number - A variable declaration
darby =
  (((350 + 17) * 13) - 9) / 2

-- Lucky number formula - A function declaration
getLuckyNumber num =
  (((num + 17) * 13) - 9) / 2

Notice the symmetry between the these two declarations: They're nearly identical apart from substituting 350 with num. But what is num? num is what we call a function parameter, it's basically a variable which belongs only to the function. We can set num to different values to change the functions calculation. We'll demonstrate how to do this below.

Paste the following function declaration at the bottom of your code editor

getLuckyNumber num =
  (((num + 13) * 13) - 9) / 4

Next, for each person's variable definition, replace the formula with getLuckyNumber followed by the random number they picked.

For example, change Darby's variable definition (on line 6) from this:

-- Darby picks 350 as his number
darby :: Int
darby = (((350 + 13) * 13) - 9) / 4 -- Change this line

to this:

-- Darby picks 350 as his number
darby :: Int
darby = getLuckyNumber 350  -- to this

What we've shown here is how num gets assigned its value. When we invoke getLuckyNumber, we add a number in front of the function (in the place where num was in the declaration), and that number gets assigned to num.

Once you've replaced every formula with getLuckyNumber, check that your code editor matches up with the section below. Resist the urge to look at the answer until you've given this your best try.

Code check

After following the above instructions, you're code editor should look like the following:

module Main where
import Prelude

-- Darby picks 350 as his number
darby :: Int
darby = getLuckyNumber 350

-- Pablo picks lucky number 17!
pablo :: Int
pablo = getLuckyNumber 17

-- Jason picks 449
jason :: Int
jason = getLuckyNumber 449

-- Dan picks 123
dan :: Int
dan = getLuckyNumber 123

getLuckyNumber num =
  (((num + 13) * 13) - 9) / 4

Notice what's happening here: Even though the lucky number formula is only written in one place, we're still able to use that formula to create each variable. Now suppose our friend comes back to us and says:

Oh jeez, sorry but it turns out the first formula I told you was actually the correct one!

Oh great! Now we have to go through and fix the formula again! But this time, things are different. We don't have to change that formula on 4 different lines anymore, we only have to fix it in the function itself. After making the fix, you should end up with this:

module Main where
import Prelude

-- Darby picks 350 as his number
darby :: Int
darby = getLuckyNumber 350

-- Pablo picks lucky number 17!
pablo :: Int
pablo = getLuckyNumber 17

-- Jason picks 449
jason :: Int
jason = getLuckyNumber 449

-- Dan picks 123
dan :: Int
dan = getLuckyNumber 123

getLuckyNumber num =
  (((num + 17) * 13) - 9) / 2

Conclusion

That concludes the first section on functions. Hopefully this first taste has given you a good sense of how useful functions can be. We'll skip the summary and questions for this section since this part was quite interactive anyways. In the next section, we'll go over how to create functions in greater detail.