Difference between revisions of "PFP Laboratory 1"
Jump to navigation
Jump to search
(Created page with "== Working environment == *Run <code>ghci</code> from the command line. it will start GHC Interpreter, the output should be something like this: </translate> <syntaxhighligh...") |
|||
(2 intermediate revisions by the same user not shown) | |||
Line 17: | Line 17: | ||
It should report a problem in function <code>plus</code> (you can not use <code>+</code> with letter, it can be repaired by removing <code>+ 'a'</code>). Report from VS Code is refreshed whenever the source file is saved on disk. | It should report a problem in function <code>plus</code> (you can not use <code>+</code> with letter, it can be repaired by removing <code>+ 'a'</code>). Report from VS Code is refreshed whenever the source file is saved on disk. | ||
+ | |||
+ | == Types == | ||
+ | |||
+ | *Using the GHCi command <code>:info</code>, learn the type of the following functions (and operators): <code>+, sqrt, succ, max</code> | ||
+ | *Get the information about the data type of following expressions and evaluate them. it is possible using the command <code>:type</code>. You can switch this option on for all commands by <code>:set +t</code> (removing by <code>:unset +t</code>). | ||
+ | </translate> | ||
+ | <syntaxhighlight lang="Haskell" > | ||
+ | 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 | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | * At presentations, we have spoken about some basic types: <code> Int, Double, Bool, Char</code>. For each of previous expressions assign them the most appropriate of these basic data types. You can verify your guess by using <code>::</code>. For example, for the first expression, let's assume it is <code>Int</code>. We can cast the result to integer and get the following result. | ||
+ | |||
+ | <syntaxhighlight lang="Haskell" class="myDark" > | ||
+ | Prelude> :type (5 + 8) :: Int | ||
+ | (5 + 8) :: Int :: Int | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | If we try incorrect conversion to <code>Char</code>, we get the following result. | ||
+ | |||
+ | <syntaxhighlight lang="Haskell" class="myDark" > | ||
+ | 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 | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | For this expression, also the type <code>Double</code> works. | ||
+ | |||
+ | <syntaxhighlight lang="Haskell" class="myDark" > | ||
+ | Prelude> :type (5 + 8) :: Double | ||
+ | (5 + 8) :: Double :: Double | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | == 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. | ||
+ | |||
+ | <syntaxhighlight lang="Haskell">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 | ||
+ | </syntaxhighlight> | ||
== First program in Haskell == | == First program in Haskell == | ||
Line 29: | Line 97: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
[[File:Tryit.png|center|60px|Try it!|link=https://rextester.com/DEAQ69276]] | [[File:Tryit.png|center|60px|Try it!|link=https://rextester.com/DEAQ69276]] | ||
+ | </div> | ||
+ | <div style="clear:both"></div> | ||
+ | |||
+ | == I Want More Functions == | ||
+ | Implement following functions: | ||
+ | * Function that computes a factorial of a given number. <div style="float: right"> [[File:Video logo.png|80px|link=https://youtu.be/WHkBFQIHmsw]]</div> | ||
+ | <syntaxhighlight lang="Haskell">factorial :: Int -> Int</syntaxhighlight> | ||
+ | |||
+ | <syntaxhighlight lang="Haskell" class="myDark"> | ||
+ | *Main> factorial 5 | ||
+ | 120 | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | <div class="mw-collapsible mw-collapsed" data-collapsetext="Hide solution" data-expandtext="Show solution"> | ||
+ | <syntaxhighlight lang="Haskell"> | ||
+ | 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) | ||
+ | </syntaxhighlight> | ||
+ | [[File:Tryit.png|center|60px|Try it!|link=https://rextester.com/WRUF28416]] | ||
+ | </div> | ||
+ | <div style="clear:both"></div> | ||
+ | |||
+ | * Function that computes n-th number in Fibonacci sequence. <div style="float: right"> [[File:Video logo.png|80px|link=https://youtu.be/GBxb_cFQG14]]</div> | ||
+ | <syntaxhighlight lang="Haskell">fib :: Int -> Int</syntaxhighlight> | ||
+ | |||
+ | <syntaxhighlight lang="Haskell" class="myDark"> | ||
+ | *Main> fib 5 | ||
+ | 8 | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | <div class="mw-collapsible mw-collapsed" data-collapsetext="Hide solution" data-expandtext="Show solution"> | ||
+ | <syntaxhighlight lang="Haskell"> | ||
+ | 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) | ||
+ | </syntaxhighlight> | ||
+ | [[File:Tryit.png|center|60px|Try it!|link=https://rextester.com/WRUF28416]] | ||
+ | </div> | ||
+ | <div style="clear:both"></div> | ||
+ | * 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). | ||
+ | <syntaxhighlight lang="Haskell">leapYear :: Int -> Bool</syntaxhighlight> | ||
+ | |||
+ | <syntaxhighlight lang="Haskell" class="myDark"> | ||
+ | *Main> leapYear 2000 | ||
+ | True | ||
+ | *Main> leapYear 2020 | ||
+ | True | ||
+ | *Main> leapYear 2100 | ||
+ | False | ||
+ | *Main> leapYear 2019 | ||
+ | False | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | <div class="mw-collapsible mw-collapsed" data-collapsetext="Hide solution" data-expandtext="Show solution"> | ||
+ | <syntaxhighlight lang="Haskell"> | ||
+ | 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 | ||
+ | </syntaxhighlight> | ||
+ | [[File:Tryit.png|center|60px|Try it!|link=https://rextester.com/WRUF28416]] | ||
+ | </div> | ||
+ | <div style="clear:both"></div> | ||
+ | * Implement two functions that returns a maximum from 2 respectively 3 given parameters. | ||
+ | <syntaxhighlight lang="Haskell"> | ||
+ | max2 :: Int -> Int -> Int | ||
+ | max3 :: Int -> Int -> Int -> Int | ||
+ | </syntaxhighlight> | ||
+ | <syntaxhighlight lang="Haskell" class="myDark"> | ||
+ | *Main> max2 5 8 | ||
+ | 8 | ||
+ | *Main> max3 5 8 4 | ||
+ | 8 | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | <div class="mw-collapsible mw-collapsed" data-collapsetext="Hide solution" data-expandtext="Show solution"> | ||
+ | <syntaxhighlight lang="Haskell"> | ||
+ | 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 | ||
+ | </syntaxhighlight> | ||
+ | [[File:Tryit.png|center|60px|Try it!|link=https://rextester.com/WRUF28416]] | ||
</div> | </div> | ||
<div style="clear:both"></div> | <div style="clear:both"></div> |
Latest revision as of 10:46, 29 September 2022
Contents
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 isInt
. 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 computesc
based on . Necessary functions can be found: Hoogle - Open
ghci
and run the implemented function with3 4
. File can be loaded using command:l
(:load
) and reloaded with:r
(:reload
).
I Want More Functions
Implement following functions:
- Function that computes a factorial of a given number.
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)
- Function that computes n-th number in Fibonacci sequence.
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)
- 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
- 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
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>