PFP Laboratory 1

From Marek Běhálek Wiki
Jump to navigation Jump to search

Working environment

  • Run ghci from the command line. it will start GHC Interpreter, the output should be something like this:

</translate>

GHCi, version 8.6.5: http://www.haskell.org/ghc/  :? for help
Prelude>
  • If you write expression, for example 1+2*3, it should be evaluated. You can close this interpreter by typing :q.
  • Open Visual Studio Code, create a file simple.hs and put there following lines of code:
doubleMe x = x * x

plus x y  = x + y + 'a'

It should report a problem in function plus (you can not use + with letter, it can be repaired by removing + 'a'). Report from VS Code is refreshed whenever the source file is saved on disk.

Types

  • Using the GHCi command :info, learn the type of the following functions (and operators): +, sqrt, succ, max
  • Get the information about the data type of following expressions and evaluate them. it is possible using the command :type. You can switch this option on for all commands by :set +t (removing by :unset +t).

</translate>

5 + 8 
3 * 5 + 8
2 + 4
sqrt 16 
succ 6
succ 7
pred 9
pred 8
sin (pi / 2)
truncate pi
round 3.5
round 3.4 
floor 3.7 
ceiling 3.3
mod 10 3
odd 3
  • At presentations, we have spoken about some basic types: Int, Double, Bool, Char. For each of previous expressions assign them the most appropriate of these basic data types. You can verify your guess by using ::. For example, for the first expression, let's assume it is Int. We can cast the result to integer and get the following result.
Prelude> :type (5 + 8) :: Int
(5 + 8) :: Int :: Int

If we try incorrect conversion to Char, we get the following result.

Prelude> :type (5 + 8) :: Char

<interactive>:1:2: error:
    * No instance for (Num Char) arising from a use of `+'
    * In the expression: (5 + 8) :: Char

For this expression, also the type Double works.

Prelude> :type (5 + 8) :: Double
(5 + 8) :: Double :: Double

Reasoning about types

For following expression, try to determine:

  • if the expression's type is correct;
  • what will be the type of the result;
  • what will be the result;
  • put the expression into the interpreter, and verify your claims.
5.9/7
(floor 5.9)/7
floor 5.9/7
fromIntegral floor 5.9/7
fromIntegral (floor 5.9)/7
div (floor 5.9) 7
(floor 5.9) div 7
(floor 5.9) `div` 7
mod 10/2 3
mod (floor (10/2)) 3

First program in Haskell

In your favorite development environment (VS Code by default):

  • Crate a file simple.hs.
  • Create a function pythagoras a b that computes c based on . Necessary functions can be found: Hoogle
  • Open ghci and run the implemented function with 3 4. File can be loaded using command :l (:load) and reloaded with :r (:reload).
pythagoras a b = sqrt (a*a + b*b)
Try it!

I Want More Functions

Implement following functions:

  • Function that computes a factorial of a given number.
    Video logo.png
factorial :: Int -> Int
*Main> factorial 5
120
factorial  :: Int -> Int
factorial  0 = 1
factorial  n = n * factorial  (n-1)

factorial'  :: Int -> Int
factorial' n | n==0 = 1
             | otherwise = n * factorial'' (n-1)

factorial''  :: Int -> Int        
factorial'' n = if n==0 then 1 else n * factorial'' (n-1)
Try it!
  • Function that computes n-th number in Fibonacci sequence.
    Video logo.png
fib :: Int -> Int
*Main> fib 5      
8
fib :: Int->Int
fib 0 = 1
fib 1 = 1
fib n = fib (n-1) + fib (n-2)

fib' :: Int -> Int
fib' n = tmp n 1 1 where
  tmp 0 a _ = a 
  tmp x a b = tmp (x-1) b (a+b)
Try it!
  • Function that checks if a year is a leap-year (divisible without remainder by 4 and it is not divisible by 100. If it is divisible by 400, it is a leap-year).
leapYear :: Int -> Bool
*Main> leapYear 2000
True
*Main> leapYear 2020
True
*Main> leapYear 2100
False
*Main> leapYear 2019
False
leapYear :: Int -> Bool
leapYear x = x `mod` 4 == 0 && x `mod` 100 /= 0 || x `mod` 400 == 0

leapYear' :: Int -> Bool
leapYear' x | x `mod` 400 == 0 = True
            | x `mod` 100 == 0 = False
            | otherwise = x `mod` 4 == 0
Try it!
  • Implement two functions that returns a maximum from 2 respectively 3 given parameters.
max2 :: Int -> Int -> Int
max3 :: Int -> Int -> Int -> Int
*Main> max2 5 8
8
*Main> max3 5 8 4
8
max2 :: Int -> Int -> Int
max2 x y | x >= y = x
         |otherwise = y

max3 :: Int -> Int -> Int -> Int
max3 x y z = (x `max2` y) `max2` z
Try it!
  • Term combination is a selection of items from a collection, such that (unlike permutations) the order of elements in this selection does not matter. Compute the number of possible combinations if we are taking k things from the collection of n things.
combinations :: Int -> Int -> Int
*Main> combinations 8 5
56
factorial  :: Int -> Int
factorial  0 = 1
factorial  n = n * factorial  (n-1)

combinations :: Int -> Int -> Int
combinations n k = factorial n `div` (factorial k * factorial (n-k))

combinations' :: Int -> Int -> Int
combinations' n k = fromIntegral(factorial n) `div` fromIntegral(factorial k * factorial (n-k))
Try it!
  • Implement a function that computes the number of solutions for a quadratic equation. This quadratic equation will be given using standard coefficients: a, b, c.
numberOfRoots :: Int -> Int -> Int -> Int
-- To simplify the solution, let construct can be used
f x y = let a = x + y
        in a * a
*Main> numberOfRoots 1 4 2
2
numberOfRoots :: Int -> Int -> Int -> Int
numberOfRoots a b c = let d = b*b - 4 * a *c
                      in if d<0 then 0 else if d == 0 then 1 else 2
Try it!
  • Implement a function that computes greatest common divider for two given numbers.
    Video logo.png
gcd' :: Int -> Int -> Int
*Main> gcd' 30 18
6
gcd' :: Int -> Int -> Int
gcd' a b | a > b = gcd' (a-b) b
         | a < b = gcd' a (b-a)
         | a==b = a

gcd2 :: Int -> Int -> Int         
gcd2 a 0 = a
gcd2 a b = gcd2 b (a `mod` b)
Try it!
  • Implement a function that compute, if a given number is a prime number.
    Video logo.png
isPrime :: Int -> Bool
*Main> isPrime 7
True
isPrime :: Int -> Bool
isPrime 1 = False
isPrime y = isPrimeTest y (y-1) where
  isPrimeTest _ 1 = True 
  isPrimeTest n x | n `mod` x ==0 = False
                  | otherwise = isPrimeTest n (x-1)
Try it!

Real first program in Haskell

If you are complaining, that all programming courses should start with printing "Hello world!" on the screen and that is why previous task sucks. Do the following exercise.

  • Crate a file firstProgram.hs with following content:
main = do putStr "Hello world!"
  • Compile it with 'GHC compiler' (command ghc).
  • It should produce an executable file firstProgram(.exe), run this file.

</translate>