Functional Programming and Intelligent Algorithms

Tutorial 1: Getting Started

Week 1: Getting started with Haskell

2 Tutorial 1: Getting Started

2.1 Step 1: Getting started

First of all, we need to get to grips with the Haskell interpreter, that is GHCi.

Do the following.

1.
Open a terminal window
2.
Start ghci on the command line
3.
Use GHCi to calculate the following expressions: 12 * 412  15 
12 * (412  15) 
1 / (2*pi) 
cos pi 
2^2 
2**0.5

Do you get the results you expect?

4.
Use GHCi to calculate the following expressions: 7 + 37 63 = (1) 3 (12 + 9) = (2) 1116 = (3) cosπ 2 = (4) 312 mod19 = (5) 0.44 = (6)

Do you get the results you expect?

5.
ghci has a number of interpreter commands which are not part of the Haskell language. Such commands start with a :. Have a look at the list of available commands by typing :help You will see some of the listed commands in use later.
6.
Exit ghci. You can use either Ctrl-D or the :quit command to exit.

2.2 Step 2: Using a script

Although ghci makes a neat calculator out of the box, that’s not quite what we want in this module. To solve complex problems we need to write our own programs, that is, define our own functions. To do this, we use separate text files, called scripts or modules, such as the following FirstScript.hs file.

1 (C) 2016: Hans Georg Schaathun <hasc@ntnu.no> 
2 
3module FirstScript where       Module header 
4 
5double :: Integer Integer   Function declaration (type) 
6double x = 2*                Function definition

The first line, and other text following a double dash (--), are comment which is ignored by GHC/GHCi. The module header (Line 3) gives the module name which has to match the file name. The function declaration (Line 5) gives the type of a new function. The double function takes an integer as input and gives an integer as output. Mathematically, we would write double : . The last line defines the double function. The return value is two times the input value x.

Do the following:

1.
Make a new directory to keep your notes and files for this first tutorial. E.g. mkdir Week01
2.
Change into the new directory. E.g. cd Week01
3.
Download the file FirstScript.hs file and put it in the current directory (Week01).
4.
Check the contents of the new file by opening it in your editor, e.g. gedit FirstScript.hs
5.
Start ghci from the command line
6.
Load the script using the :load command: :load FirstScript

Note that the extension .hs may be omitted.

7.
Test the function by typing double 5
8.
Try the following double 2.5

What happens? Remember the function declaration. What input does double accept?

2.3 Step 3: Making a script

Now, you are going to make your own simple script/module from scratch.

1.
Make sure that you are in the Week01 directory which you used in the previous step. You can do this with the following command which prints the absolute path to the current directory: pwd
2.
Open an editor to edit a Haskell file. E.g. gedit MyFirstScript.hs

The name of a Haskell file (script) have to end with .hs and should start with an upper-case letter. E.g. MyFirstScript.hs.

3.
Start with a comment at the top of your file to claim authorship, e.g.  John Doe <john@doe.nowhere.invalid>

Comments are ignored by the compiler or interpreter, and are purely a help for human readers.

4.
Define a new module by adding a module header under the comment module MyFirstScript where

Note that the module name must match the filename without the .hs extension.

5.
Define your first function inside the greet :: String String 
greet name = "Hello,␣" ++ name
6.
Save the file
7.
Start ghci from the command line
8.
Load your script, e.g. :l MyFirstScript

:l is shorthand for :load.

9.
Test the function greet "John"
10.
You can add more functions to your module. Do not close ghci. Use a different window to add a new function to your module. square :: Int > Int 
square n = n*n
11.
Returning to ghci, reload the module using :reload
12.
Test the new function: square 2 
square 5

2.4 Step 4: Working with Integers

One of the fundamental data types is integers. In fact Haskell has two integer types, namely Int and Integer. We shall make a little experiment to see the difference.

1.
Open your text editor with a new file, IntTest.hs is a good name.
2.
Define a function to do exponentiation of Integer. pow1 :: Integer Integer Integer 
pow1 x y = x^y
3.
Define another function to do exponentiation of Int. pow2 :: Int Int Int 
pow2 x y = x^y
4.
Open ghci and load the module you just created.
5.
Test the two functions, with small and big arguments. pow1 2 10 
pow2 2 10 
pow1 2 65 
pow2 2 65 
pow1 3 39 
pow2 3 39

What happens? Why do pow1 and pow2 give different answers? Discuss answers with your class mates.

2.5 Step 5: Working with Booleans

Boolean is another fundamental data type, with two possible values, True or False.

1.
Open your editor to create a new Haskell module, e.g. BoolTest.hs
2.
Add the customary comment to identify yourself as author and the module header.
3.
Add a couple of functions: myNot :: Bool Bool 
myNot False = True 
myNot True = False 
 
myAnd :: Bool Bool Bool 
myAnd True True = True 
myAnd _ _ = False

Both functions are standard logical operators, the negation (not) and the conjunciton (and).

4.
Start ghci, load your module, and test the above functions, e.g. myNot False 
myNot True 
myAnd False False 
myAnd False True 
myAnd True False 
myAnd True True

Are you happy with the results?

5.
Add functions for logical or (myOr) and exclusive or (myXOR) to your module using pattern matching and literals. There is more than one way of doing it, so just think about the mathematical (logical) meaning and do it your way.
6.
Reload your module and test the new functions. Do they work as intended?

2.6 Step 6: Working with Floating Point Numbers

Many of our algorithms work on real numbers. Unfortunately, the computer does not support real numbers. Instead we have to work with floating point numbers. There are two floating point data types in common use. In Haskell, they are called Float and Double, but they are defined by the CPU architecture and not by the language. Let’s explore this

1.
Why cannot computers work with real numbers?
2.
Start ghci
3.
Compare the following expressions 2**500 :: Double 
2**500 :: Float 
2**(500) :: Double 
2**(500) :: Float

The floating point types permit a couple of non-numeric values, namely ±Infinity, and NaN (Not a Number).

4.
Evaluate each of the following Haskell expressions using GHCi. What value do you expect to get? What value do you actually get? 1/0 
0/0 
isNaN (log (1)) 
(log (1)) == (log (1)) 
(1/0)*
isInfinite (0/0) 
isInfinite (1/0)

NaN values will usually just propagate through floating point operations, so that NaN in gives NaN out. However, some operations have unpredictable results, so you should check for NaN whenever there is a risk that NaN has occured.

5.
What value do you get from the following expressions: ceiling (log (1)) 
ceiling (0/0) 
floor (0/0)

2.7 Step 7: Prefix and in-fix notation

We have seen a couple of functions. For instance:

cos 1 
pow1 2 10 
pow2 2 10
They are evaluated by writing the function name first, and then a string of arguments. This is called prefix notation, since the function name prefixes the arguments.

We have also seen a couple of operators. For instance

2 + 2 
* 5 
6 / 2
They are evaluated by writing the operator symbol between two operands. This is called in-fix notation.

1.
Try the following expressions in GHCi and compare: 2 + 2 
(+) 2 2
2.
Try the following expressions and compare: * 5 
(*) 3 5
3.
Try the following expressions and compare: 6 / 2 
(/) 6 2
4.
Make sure that you have loaded the module defining pow1 and pow2. Try the following expressions and compare: pow1 6 2 
6 ‘pow1‘ 2
5.
Try the following expressions and compare: pow2 2 3 
2 ‘pow1‘ 3
6.
Try the following expressions and compare: 32 ‘mod‘ 10 
mod 32 10
7.
Try the following expressions and compare: 32 ‘div‘ 10 
div 32 10
8.
Discuss What is the difference between an operator and a function?


7th April 2017
Hans Georg Schaathun / hasc@ntnu.no