Haskell Course - Lesson 3 - Numbers
We'll study numbers first because they are one of the most useful types in Haskell. After this lesson, you'll understand 4 new types and learn how to use Haskell as your personal calculator. 🤓
Common numeric types in Haskell
Not all numbers are the same. And in Haskell, we have four different numeric types: Int
, Integer
, Float
, and Double
.
Int
and Integer
Both Int
and Integer
are types that represent whole numbers (i.e., 3
can be an Int
or Integer
, but 3.2
can't).
The difference between Int
and Integer
is the size of the numbers that it can store. Integer
can hold numbers as big or small as your computer can handle. But Int
has a maximum value of 263 (that's 2x2x2x2x2... 63 times 👀, big enough for most cases, if you ask me) and a minimum value of -263.
I assume that you can do the math in your head to know how big is that number.
Just kidding 🤣 , we can ask Haskell to do the math for us. Open ghci
in your terminal (like we saw in lesson 1), write 2^62
, and hit enter:
2^62 -- This will give you: 4611686018427387904
Haskell calculates the number for us! Awesome! Now, let's indicate that this number "has type of" Int
and try again:
2^62 :: Int -- This will also give you: 4611686018427387904
So far, so good. Now, let's try with a bigger number. Let's say 264:
2^64 :: Int -- Oh no! This will give you: 0! 👀
You can try with larger numbers, too! As you can see, numbers greater than 263 are too big for Int
and are lost. But, if we try one of those numbers as Integer
, we get the correct result:
2^69 :: Integer -- This will give you: 590295810358705651712 😏
There you go! 😎 No more unexpected zeroes.
So, why do we need Int
if Integer
can do the same and has no limits? Because Int
is more efficient. The program runs faster if we use Int
.
What does all this mean to you?
- If you know you're going to work with small (smaller than ±263) whole numbers, use
Int
. Else, useInteger
. - If a function returns an
Int
orInteger
, you can be sure that it'll be a whole number.
But what about the rest of the numbers? What about numbers with decimal point (with fractional value) like 4.5?
Float
and Double
Both Float
and Doube
are real
Floating-point number
A floating-point number is one where the position of the decimal point can "float" rather than being in a fixed position within a number. Examples of floating-point numbers are 1.23, 87.425, and 9039454.2.
The difference is the level of precision that they have. Float
has
Single precision floating-point
Basic format of floating-point number that uses ~7 decimal digits to represent the number. Usually occupying 32 bits in computre memory.
Double
has (you guessed it) double the Float
's precision.Theoretically, the reasons as to when to use one or de other are somewhat analogous to the Int
and Integer
cases. Double
has double the precision but hogs more memory because it uses twice as many bits to represent numbers.
Recommendation based on real-world use: Don't use Float
. Use Double
. There's rarely a speed disadvantage in modern computers, and with Double
, you are much less likely to shoot yourself in the foot with rounding errors.
Let's see what happens if I want to show the first 20 digits of pi (π) in ghci
:
3.14159265358979323846 :: Float -- Result: 3.1415927
With Float
, I get 7 digits after the point.
3.14159265358979323846 :: Double -- Result: 3.141592653589793
With Double
I get 15 digits after the point (double the previous precision).
And what if I don't specify the type?
3.14159265358979323846 -- Result: 3.141592653589793
Haskell assumes that you want the best precision possible and infers that you want to use a Double
.
Ok. Those are Haskells standard numeric types. Now let's do some simple calculations!
Doing some simple calculations
Here are a few math operations in Haskell and its correspondent symbol and example:
Operation | Haskell Symbol | Example |
---|---|---|
Addition | + | 3 + 2 |
Subtraction | - | 3 - 2 |
Multiplication | * | 3 * 2 |
Division | / | 3 / 2 |
Exponential | ^ | 4 ^ 3 |
Remember that operations have an order (division before addition and such). And in Haskell—the same as in maths—you can alter the order by applying parenthesis:
6 + 4 / 2 = 8
(6 + 4) / 2 = 5
Now, we can use ghci
as our personal calculator.
Calculating the volume of a cube
The formula to calculate the volume of a cube is volume = side3
. This means that to obtain the volume of a cube, we just need to calculate the cube of its side. If we have a cube with 2 meters (2m) of side length, the volume of the cube will be: side3 = 23 = 8
.
And to calculate the volume of a cube of side length 3m, we have to write:
3^3 -- That will give me a volume of 27m3
Note: You can navigate through everything you executed in ghci
using your arrow keys! Up goes back to previous expressions, and down goes forward to newer expressions.
Ok, that was the warm-up.
8^3
= 512m3
I know, I know. That was too easy. Let's do something more interesting.
Increasing the difficulty
I'll provide the expression in the form of a sentence, and you have to translate it into a valid Haskell expression in GHCi and check the result:
(22-13)/3
= 3.0
12/4 + 4^2
= 19.0
3^9 - 943*500
= -451817
Notice that Haskell returns the first and second results as a floating-point number (.0
) even if the results are whole numbers. But, in the last one, Haskell returns a whole number (without .0
). Why is that?
Because Haskell knows (before calculating the result) that if you add two whole numbers, the result will always be a whole number. Same with subtraction and exponential. But there are many cases when a division of whole numbers gives you fractional numbers (i.e., 3/2
gives you 1.5
). So, Haskell makes sure that the division never fails by transforming the numbers to Float
or Double
before dividing.
We'll learn the specifics of how Haskell does this in the "Type classes" lesson.
Ok, we're going to stop here. But you're not done yet! Make sure to complete this week's homework! See ya in the next lesson! 💪😄
Homework
- Get familiar with the order of operations and take a peek at the programming languages section.
2. Fahrenheit to Celsius
Celsius (ºC)—also referred to as centigrade—is the most common non-scientific unit of temperature. But, the US still uses Fahrenheit (ºF). Let's say that you have friends in the US and, when chatting, they always comment about their temperature in Fahrenheit. You got tired of doing the math in your head, and you decide to use Haskell.
This is the formula to transform from Fahrenheit to Celsius: Tc = (Tf - 32)*5/9
. Where Tc
is the temperature in Celsius (the result) and Tf
is the temperature in Fahrenheit. Using only ghci
transform the temperatures to Celsius:
- How many ºC is
100
ºF? - How many ºC is
32
ºF? - How many ºC is
212
ºF?
You are doing great! With each lesson, you get closer and closer to becoming a full-fledged programmer! 🔥 Next lesson, we'll learn about characters, lists, and Strings! See you there! 😄
PD: If you find this course valuable, please share it so more people can learn! 😄