Add files for lab 01
This commit is contained in:
parent
dffb3bdce3
commit
3bb0b1ead0
8 changed files with 1486 additions and 0 deletions
222
Exercises/exercise-1/Code/A_Basics.hs
Normal file
222
Exercises/exercise-1/Code/A_Basics.hs
Normal file
|
@ -0,0 +1,222 @@
|
||||||
|
{- Contents
|
||||||
|
A short introduction to Haskell;
|
||||||
|
The very basics
|
||||||
|
-}
|
||||||
|
|
||||||
|
|
||||||
|
-----------------------------------------------------------
|
||||||
|
-- Comments
|
||||||
|
-----------------------------------------------------------
|
||||||
|
|
||||||
|
-- a single line comment
|
||||||
|
|
||||||
|
{- a multiline comment
|
||||||
|
{- can be nested -}
|
||||||
|
-}
|
||||||
|
|
||||||
|
{- Usually (from now on), we will try to adhere to the
|
||||||
|
following convention/structure for multiline comments:
|
||||||
|
-}
|
||||||
|
|
||||||
|
{- Optional "title" of the comment
|
||||||
|
Content of the comment possibly spanning multiple lines
|
||||||
|
with length <= 60.
|
||||||
|
-}
|
||||||
|
|
||||||
|
|
||||||
|
-----------------------------------------------------------
|
||||||
|
-- Simple declarations
|
||||||
|
-----------------------------------------------------------
|
||||||
|
|
||||||
|
{- Declaring a variable
|
||||||
|
Generally, in Haskell we define the type of a variable
|
||||||
|
in a separate line before we define the variable.
|
||||||
|
-}
|
||||||
|
|
||||||
|
-- 'five' is the integer 5
|
||||||
|
five :: Integer
|
||||||
|
five = 5
|
||||||
|
|
||||||
|
{-
|
||||||
|
'six' is the integer 6. The type 'Integer' can
|
||||||
|
accomodate integers of arbitrary size
|
||||||
|
-}
|
||||||
|
six :: Integer
|
||||||
|
six = 6
|
||||||
|
|
||||||
|
-- 'four' is the float 4.0
|
||||||
|
four :: Float
|
||||||
|
four = 4
|
||||||
|
|
||||||
|
|
||||||
|
-----------------------------------------------------------
|
||||||
|
---- Numeric operations
|
||||||
|
-----------------------------------------------------------
|
||||||
|
|
||||||
|
seven :: Integer
|
||||||
|
seven = five + 2
|
||||||
|
|
||||||
|
theIntEight :: Integer
|
||||||
|
theIntEight = 3 + five
|
||||||
|
|
||||||
|
theFloatSeven :: Float
|
||||||
|
theFloatSeven = 3 + four
|
||||||
|
|
||||||
|
twentyFour :: Float
|
||||||
|
twentyFour = 3 * 2 ^ 3
|
||||||
|
|
||||||
|
{- Integer division
|
||||||
|
'div' denotes integer division. Generally, it is
|
||||||
|
possible to write a function between '`' to use infix
|
||||||
|
notation. I order to define functions that are
|
||||||
|
"natively" infix, you would use brackets '(...)' when
|
||||||
|
defining the function/operator.
|
||||||
|
-}
|
||||||
|
intSevenByThree :: Integer
|
||||||
|
intSevenByThree = seven `div` 3
|
||||||
|
|
||||||
|
{- Division
|
||||||
|
The "normal" division '/' is for "fractional numbers,
|
||||||
|
e.g. floats.
|
||||||
|
-}
|
||||||
|
floatSevenByThree :: Float
|
||||||
|
floatSevenByThree = 7 / 3
|
||||||
|
|
||||||
|
{- Exercise
|
||||||
|
Fill out the types, check your solutions with the REPL.
|
||||||
|
|
||||||
|
x :: Integer
|
||||||
|
x = 2 ^ 3
|
||||||
|
|
||||||
|
y :: Float
|
||||||
|
y = 2.0 ^ 3
|
||||||
|
|
||||||
|
a :: Integer
|
||||||
|
a = x + 5
|
||||||
|
|
||||||
|
b :: Float
|
||||||
|
b = y/2
|
||||||
|
|
||||||
|
c :: Does not work
|
||||||
|
c = y `div` 3
|
||||||
|
-}
|
||||||
|
|
||||||
|
|
||||||
|
-----------------------------------------------------------
|
||||||
|
---- Booleans and boolean operations
|
||||||
|
-----------------------------------------------------------
|
||||||
|
|
||||||
|
true :: Bool
|
||||||
|
true = True
|
||||||
|
|
||||||
|
false :: Bool
|
||||||
|
false = False
|
||||||
|
|
||||||
|
alsoTrue :: Bool
|
||||||
|
alsoTrue = true || false
|
||||||
|
|
||||||
|
alsoFalse :: Bool
|
||||||
|
alsoFalse = true && false
|
||||||
|
|
||||||
|
moreTruth :: Bool
|
||||||
|
moreTruth = not alsoFalse
|
||||||
|
|
||||||
|
|
||||||
|
-----------------------------------------------------------
|
||||||
|
---- Strings and chars
|
||||||
|
-----------------------------------------------------------
|
||||||
|
|
||||||
|
aChar :: Char
|
||||||
|
aChar = 'a'
|
||||||
|
|
||||||
|
aString :: String
|
||||||
|
aString = "Happy new year"
|
||||||
|
|
||||||
|
greeting :: String
|
||||||
|
greeting = aString ++ " " ++ "2022"
|
||||||
|
|
||||||
|
greeting2 :: String
|
||||||
|
greeting2 = concat
|
||||||
|
[ aString
|
||||||
|
, " "
|
||||||
|
, "2022"
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{- Warning
|
||||||
|
The operators are strongly typed; they can only digest
|
||||||
|
values of the same type. The following declarations are
|
||||||
|
thus rejected by the type checker:
|
||||||
|
|
||||||
|
aString = "Happy new year"
|
||||||
|
greeting = aString ++ " " ++ 2022
|
||||||
|
|
||||||
|
five :: Int
|
||||||
|
five = 5
|
||||||
|
seven = five + 2.0
|
||||||
|
-}
|
||||||
|
|
||||||
|
|
||||||
|
-----------------------------------------------------------
|
||||||
|
---- Lists
|
||||||
|
-----------------------------------------------------------
|
||||||
|
|
||||||
|
{-
|
||||||
|
We will often use `List` (linked lists), a generic
|
||||||
|
container to hold multiple values of *the same type*.
|
||||||
|
-}
|
||||||
|
|
||||||
|
aListOfStrings :: [String]
|
||||||
|
aListOfStrings = [ "one", "two", "three" ]
|
||||||
|
|
||||||
|
aListOfInts :: [Integer]
|
||||||
|
aListOfInts = [ 1, 2, 3 ]
|
||||||
|
|
||||||
|
{- Exercise
|
||||||
|
Fill out the type, check your solutions with the REPL.
|
||||||
|
|
||||||
|
friendGroups :: [[String]]
|
||||||
|
friendGroups =
|
||||||
|
[ ["Peter", "Anna", "Roman", "Laura"]
|
||||||
|
, ["Anna","Reto"]
|
||||||
|
, ["Christoph", "Mara", "Andrew"]
|
||||||
|
]
|
||||||
|
-}
|
||||||
|
|
||||||
|
{- List comprehension
|
||||||
|
Aside from declaring lists explicitly by writing down
|
||||||
|
their element (as shown before), lists can also be
|
||||||
|
declared by "list comprehension" and also as "ranges".
|
||||||
|
-}
|
||||||
|
|
||||||
|
someInts :: [Integer]
|
||||||
|
someInts = [1..15] -- range
|
||||||
|
|
||||||
|
someEvens :: [Integer]
|
||||||
|
someEvens = [ 2*x | x <- [-5..5]]
|
||||||
|
|
||||||
|
pairs :: [(Integer, Bool)]
|
||||||
|
pairs = [ (x,y) | x <- [0..5], y <- [True, False]]
|
||||||
|
|
||||||
|
lessThanPairs :: [(Integer,Integer)]
|
||||||
|
lessThanPairs = [ (x,y)
|
||||||
|
| x <- [0..5]
|
||||||
|
, y <- [0..5]
|
||||||
|
, x < y -- guard
|
||||||
|
, x > 1 -- second guard
|
||||||
|
]
|
||||||
|
|
||||||
|
{- Exercise
|
||||||
|
Use list comprehension to declare a list that contains
|
||||||
|
all square numbers between 1 and 100.
|
||||||
|
-}
|
||||||
|
squares :: [Integer]
|
||||||
|
squares = [ x*x | x <- [1..10]]
|
||||||
|
|
||||||
|
{- Exercise
|
||||||
|
Use list comprehension to declare a list that contains
|
||||||
|
all odd square numbers between 1 and 100.
|
||||||
|
-}
|
||||||
|
oddSquares :: [Integer]
|
||||||
|
oddSquares = [ x | x <- squares, x `mod` 2 /= 0 ]
|
225
Exercises/exercise-1/Code/A_BasicsTodo.hs
Normal file
225
Exercises/exercise-1/Code/A_BasicsTodo.hs
Normal file
|
@ -0,0 +1,225 @@
|
||||||
|
{- Contents
|
||||||
|
A short introduction to Haskell;
|
||||||
|
The very basics
|
||||||
|
-}
|
||||||
|
|
||||||
|
|
||||||
|
-----------------------------------------------------------
|
||||||
|
-- Comments
|
||||||
|
-----------------------------------------------------------
|
||||||
|
|
||||||
|
-- a single line comment
|
||||||
|
|
||||||
|
{- a multiline comment
|
||||||
|
{- can be nested -}
|
||||||
|
-}
|
||||||
|
|
||||||
|
{- Usually (from now on), we will try to adhere to the
|
||||||
|
following conventuion/structure for multiline comments:
|
||||||
|
-}
|
||||||
|
|
||||||
|
{- Optional "title" of the comment
|
||||||
|
Content of the comment possibly spaning multiple lines
|
||||||
|
with length <= 60.
|
||||||
|
-}
|
||||||
|
|
||||||
|
|
||||||
|
-----------------------------------------------------------
|
||||||
|
-- Simple declarations
|
||||||
|
-----------------------------------------------------------
|
||||||
|
|
||||||
|
{- Declaring a variable
|
||||||
|
Generally, in Haskell we define the type of a variable
|
||||||
|
in a separate line before we define the variable.
|
||||||
|
-}
|
||||||
|
|
||||||
|
-- 'five' is the integer 5
|
||||||
|
five :: Integer
|
||||||
|
five = 5
|
||||||
|
|
||||||
|
{-
|
||||||
|
'six' is the integer 6. The type 'Integer' can
|
||||||
|
accomodate integers of arbitrary size
|
||||||
|
-}
|
||||||
|
six :: Integer
|
||||||
|
six = 6
|
||||||
|
|
||||||
|
-- 'four' is the float 4.0
|
||||||
|
four :: Float
|
||||||
|
four = 4
|
||||||
|
|
||||||
|
|
||||||
|
-----------------------------------------------------------
|
||||||
|
---- Numeric operations
|
||||||
|
-----------------------------------------------------------
|
||||||
|
|
||||||
|
seven :: Integer
|
||||||
|
seven = five + 2
|
||||||
|
|
||||||
|
theIntEight :: Integer
|
||||||
|
theIntEight = 3 + five
|
||||||
|
|
||||||
|
theFloatSeven :: Float
|
||||||
|
theFloatSeven = 3 + four
|
||||||
|
|
||||||
|
twentyFour :: Float
|
||||||
|
twentyFour = 3 * 2 ^ 3
|
||||||
|
|
||||||
|
{- Integer division
|
||||||
|
'div' denotes integer division. Generally, it is
|
||||||
|
possible to write a function between '`' to use infix
|
||||||
|
notation. I order to define functions that are
|
||||||
|
"natively" infix, you would use brackets '(...)' when
|
||||||
|
defining the function/operator.
|
||||||
|
-}
|
||||||
|
intSevenByThree :: Integer
|
||||||
|
intSevenByThree = seven `div` 3
|
||||||
|
|
||||||
|
{- Division
|
||||||
|
The "normal" division '/' is for "fractional numbers,
|
||||||
|
e.g. floats.
|
||||||
|
-}
|
||||||
|
floatSevenByThree :: Float
|
||||||
|
floatSevenByThree = 7 / 3
|
||||||
|
|
||||||
|
{- Exercise
|
||||||
|
Fill out the types where possible
|
||||||
|
Check your solutions with the REPL.
|
||||||
|
|
||||||
|
|
||||||
|
x :: Integer
|
||||||
|
x = 2 ^ 3
|
||||||
|
|
||||||
|
y :: Float
|
||||||
|
y = 2.0 ^ 3
|
||||||
|
|
||||||
|
a :: ?
|
||||||
|
a = x + 5
|
||||||
|
|
||||||
|
b :: ?
|
||||||
|
b = y/2
|
||||||
|
|
||||||
|
c :: ?
|
||||||
|
c = y `div` 3
|
||||||
|
|
||||||
|
-}
|
||||||
|
|
||||||
|
|
||||||
|
-----------------------------------------------------------
|
||||||
|
---- Booleans and boolean operations
|
||||||
|
-----------------------------------------------------------
|
||||||
|
|
||||||
|
true :: Bool
|
||||||
|
true = True
|
||||||
|
|
||||||
|
false :: Bool
|
||||||
|
false = False
|
||||||
|
|
||||||
|
alsoTrue :: Bool
|
||||||
|
alsoTrue = true || false
|
||||||
|
|
||||||
|
alsoFalse :: Bool
|
||||||
|
alsoFalse = true && false
|
||||||
|
|
||||||
|
moreTruth :: Bool
|
||||||
|
moreTruth = not alsoFalse
|
||||||
|
|
||||||
|
|
||||||
|
-----------------------------------------------------------
|
||||||
|
---- Strings and chars
|
||||||
|
-----------------------------------------------------------
|
||||||
|
|
||||||
|
aChar :: Char
|
||||||
|
aChar = 'a'
|
||||||
|
|
||||||
|
aString :: String
|
||||||
|
aString = "Happy new year"
|
||||||
|
|
||||||
|
greeting :: String
|
||||||
|
greeting = aString ++ " " ++ "2022"
|
||||||
|
|
||||||
|
greeting2 :: String
|
||||||
|
greeting2 = concat
|
||||||
|
[ aString
|
||||||
|
, " "
|
||||||
|
, "2022"
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{- Warning
|
||||||
|
The operators are strongly typed; they can only digest
|
||||||
|
values of the same type. The following declarations are
|
||||||
|
thus rejected by the type checker:
|
||||||
|
|
||||||
|
aString = "Happy new year"
|
||||||
|
greeting = aString ++ " " ++ 2022
|
||||||
|
|
||||||
|
five :: Int
|
||||||
|
five = 5
|
||||||
|
seven = five + 2.0
|
||||||
|
-}
|
||||||
|
|
||||||
|
|
||||||
|
-----------------------------------------------------------
|
||||||
|
---- Lists
|
||||||
|
-----------------------------------------------------------
|
||||||
|
|
||||||
|
{-
|
||||||
|
We will often use `List` (linked lists), a generic
|
||||||
|
container to hold multiple values of *the same type*.
|
||||||
|
-}
|
||||||
|
|
||||||
|
aListOfStrings :: [String]
|
||||||
|
aListOfStrings = [ "one", "two", "three" ]
|
||||||
|
|
||||||
|
aListOfInts :: [Integer]
|
||||||
|
aListOfInts = [ 1, 2, 3 ]
|
||||||
|
|
||||||
|
{- Exercise
|
||||||
|
Fill out the type, check your solutions with the REPL.
|
||||||
|
|
||||||
|
friendGroups :: ?
|
||||||
|
friendGroups =
|
||||||
|
[ ["Peter", "Anna", "Roman", "Laura"]
|
||||||
|
, ["Anna","Reto"]
|
||||||
|
, ["Christoph", "Mara", "Andrew"]
|
||||||
|
]
|
||||||
|
-}
|
||||||
|
|
||||||
|
{- List comprehension
|
||||||
|
Aside from declaring lists explicitly by writing down
|
||||||
|
their element (as shown before), lists can also be
|
||||||
|
declared by "list comprehension" and also as "ranges".
|
||||||
|
-}
|
||||||
|
|
||||||
|
someInts :: [Integer]
|
||||||
|
someInts = [1..15] -- range
|
||||||
|
|
||||||
|
someEvens :: [Integer]
|
||||||
|
someEvens = [ 2*x | x <- [-5..5]]
|
||||||
|
|
||||||
|
pairs :: [(Integer, Bool)]
|
||||||
|
pairs = [ (x,y) | x <- [0..5], y <- [True, False]]
|
||||||
|
|
||||||
|
lessThanPairs :: [(Integer,Integer)]
|
||||||
|
lessThanPairs = [ (x,y)
|
||||||
|
| x <- [0..5]
|
||||||
|
, y <- [0..5]
|
||||||
|
, x < y -- guard
|
||||||
|
, x > 1 -- second guard
|
||||||
|
]
|
||||||
|
|
||||||
|
{- Exercise
|
||||||
|
Use list comprehension to declare a list that contains
|
||||||
|
all square numbers between 1 and 100.
|
||||||
|
-}
|
||||||
|
squares :: [Integer]
|
||||||
|
squares = error "fixme"
|
||||||
|
|
||||||
|
{- Exercise
|
||||||
|
Use list comprehension to declare a list that contains
|
||||||
|
all odd square numbers between 1 and 100.
|
||||||
|
-}
|
||||||
|
oddSquares :: [Integer]
|
||||||
|
oddSquares = error "fixme"
|
202
Exercises/exercise-1/Code/B_Functions.hs
Normal file
202
Exercises/exercise-1/Code/B_Functions.hs
Normal file
|
@ -0,0 +1,202 @@
|
||||||
|
{- Contents
|
||||||
|
A short integerroduction to Haskell;
|
||||||
|
On how to create simple functions.
|
||||||
|
-}
|
||||||
|
|
||||||
|
-----------------------------------------------------------
|
||||||
|
-- Elementary Functions
|
||||||
|
-----------------------------------------------------------
|
||||||
|
|
||||||
|
{- General Syntax for functions
|
||||||
|
* Input on the left, output on the right.
|
||||||
|
* Functions also have a type: input type on the left
|
||||||
|
side, output type on the right side, arrow inbetween.
|
||||||
|
-}
|
||||||
|
inc1 :: Integer -> Integer
|
||||||
|
inc1 n = n + 1
|
||||||
|
|
||||||
|
{- Lambda notation
|
||||||
|
Everything can also be written on the right side (lambda
|
||||||
|
notation). In fact, `inc1` is just syntactic sugar for
|
||||||
|
`inc2`.
|
||||||
|
-}
|
||||||
|
inc2 :: Integer -> Integer
|
||||||
|
inc2 = \n -> n + 1
|
||||||
|
|
||||||
|
{- Function application
|
||||||
|
To apply a function, write the function to the left of
|
||||||
|
the input/argument (no brackets needed).
|
||||||
|
-}
|
||||||
|
two :: Integer
|
||||||
|
two = inc1 1
|
||||||
|
|
||||||
|
someGreeting :: String -> String
|
||||||
|
someGreeting person = "Hello " ++ person
|
||||||
|
|
||||||
|
|
||||||
|
{- Exercise
|
||||||
|
Define a function `square`, that squares the given input
|
||||||
|
and write down its type. Define the same function using
|
||||||
|
the lambda notation.
|
||||||
|
-}
|
||||||
|
square :: Integer -> Integer
|
||||||
|
square x = x * x
|
||||||
|
|
||||||
|
|
||||||
|
-----------------------------------------------------------
|
||||||
|
-- Functions of Several Variables
|
||||||
|
-----------------------------------------------------------
|
||||||
|
|
||||||
|
{- Tupled Inputs
|
||||||
|
'addTupled' is binary function, its output depends on
|
||||||
|
two separate integers.
|
||||||
|
-}
|
||||||
|
addTupled :: (Integer, Integer) -> Integer
|
||||||
|
addTupled (x, y) = x + y
|
||||||
|
|
||||||
|
{-
|
||||||
|
'avg3Tupled' is a function that depends on three input
|
||||||
|
variables.
|
||||||
|
-}
|
||||||
|
avg3Tupled :: (Float, Float, Float) -> Float
|
||||||
|
avg3Tupled ( x, y, z ) = (x + y + z) / 3
|
||||||
|
|
||||||
|
{- Evaluating with Tuples
|
||||||
|
We evaluate a function of several variables by providing
|
||||||
|
values *for each* input variabele.
|
||||||
|
-}
|
||||||
|
four :: Float
|
||||||
|
four = avg3Tupled ( 3, 4, 5 )
|
||||||
|
|
||||||
|
{-
|
||||||
|
If we want to evaluate a multivariable function before
|
||||||
|
we have all inputs ready, we have to properly
|
||||||
|
parametrize it. We can do this with curried functions.
|
||||||
|
More on that later!
|
||||||
|
-}
|
||||||
|
|
||||||
|
|
||||||
|
{- A Curried Function
|
||||||
|
'add' is the parametrized (a.k.a curried) version of
|
||||||
|
`add`. It is a function that returns a (unary) function.
|
||||||
|
|
||||||
|
Note that the following three lines are equivalent
|
||||||
|
declarations:
|
||||||
|
|
||||||
|
'add = \x -> \y -> x + y'
|
||||||
|
|
||||||
|
'add x = \y -> x + y'
|
||||||
|
|
||||||
|
'add x y = x + y'
|
||||||
|
|
||||||
|
Also note that the parenthesis are not needed in the
|
||||||
|
declaration of the type of 'add'.
|
||||||
|
-}
|
||||||
|
add :: Int -> (Int -> Int)
|
||||||
|
add n m = n + m
|
||||||
|
|
||||||
|
|
||||||
|
{- Partial Application
|
||||||
|
'add3' is the function that adds '3' to any given input.
|
||||||
|
Thanks to currying, we can realize 'add3' as a special
|
||||||
|
case of 'add'. Thanks to partial application, this
|
||||||
|
corresponds to a single function call.
|
||||||
|
-}
|
||||||
|
add3 :: Int -> Int
|
||||||
|
add3 = add 3
|
||||||
|
|
||||||
|
{- Exercise
|
||||||
|
Declare a curried version of the function 'avg3Tupled'
|
||||||
|
as a lambda term.
|
||||||
|
-}
|
||||||
|
avg3 :: Float -> Float -> Float -> Float
|
||||||
|
-- avg3 x y z = (x + y + z) / 3
|
||||||
|
-- avg3 x y = \ z -> (x + y + z) / 3
|
||||||
|
-- avg3 x = \y z -> (x + y + z) /3
|
||||||
|
avg3 = \x -> \y -> \z -> (x + y + z) / 3
|
||||||
|
|
||||||
|
{- Exercise
|
||||||
|
use the binary function '(++)' that concatenates strings
|
||||||
|
to specify a function that prepends "=> " to any given
|
||||||
|
input string. Use partial application
|
||||||
|
-}
|
||||||
|
prepArrow :: String -> String
|
||||||
|
prepArrow = (++) "=> "
|
||||||
|
|
||||||
|
|
||||||
|
-----------------------------------------------------------
|
||||||
|
-- Higher Order Functions
|
||||||
|
-----------------------------------------------------------
|
||||||
|
|
||||||
|
{- Function as Input
|
||||||
|
'apply' is a function that accepts a function as input
|
||||||
|
(and applies it to the remaining input)
|
||||||
|
-}
|
||||||
|
apply :: (a -> b) -> a -> b
|
||||||
|
apply f x = f x
|
||||||
|
|
||||||
|
{- Function as Input and Output
|
||||||
|
'twice' is a function that accepts and returns a
|
||||||
|
function.
|
||||||
|
-}
|
||||||
|
twice :: (a -> a) -> (a -> a)
|
||||||
|
twice f x = f (f x)
|
||||||
|
-- twice = f . f
|
||||||
|
|
||||||
|
{- Exercise
|
||||||
|
Write a function `thrice` that applies a function three
|
||||||
|
times.
|
||||||
|
-}
|
||||||
|
thrice :: (a -> a) -> a -> a
|
||||||
|
thrice f x = f (twice f x)
|
||||||
|
-- thrice f = f . f . f
|
||||||
|
|
||||||
|
{- Exercise
|
||||||
|
Write a function 'compose' that accepts two functions
|
||||||
|
and applies them to a given argument in order.
|
||||||
|
-}
|
||||||
|
compose :: (a -> b) -> (b -> c) -> a -> c
|
||||||
|
compose f g x = g (f x)
|
||||||
|
|
||||||
|
{- Exercise
|
||||||
|
reimplement 'twice' and 'thrice' with as an application
|
||||||
|
of the function 'compose'.
|
||||||
|
-}
|
||||||
|
twiceByComp :: (a -> a) -> a -> a
|
||||||
|
twiceByComp f = compose f f
|
||||||
|
|
||||||
|
thriceByComp :: (a -> a) -> a -> a
|
||||||
|
thriceByComp f = compose f (twiceByComp f)
|
||||||
|
|
||||||
|
{- List map
|
||||||
|
A often used higher function is ``mapping'' of lists.
|
||||||
|
This function will apply a function (given as an
|
||||||
|
argument) to every element in a list (also given as an
|
||||||
|
argument) and return a new list containig the changed
|
||||||
|
values. There are a lot of other functions to work
|
||||||
|
with lists (and similar types). We will learn about
|
||||||
|
these functions later.
|
||||||
|
-}
|
||||||
|
mapping :: [Integer]
|
||||||
|
mapping = map (\n -> n + 1) [1, 2, 3]
|
||||||
|
|
||||||
|
{-| Exercise
|
||||||
|
greet all friends using 'friends', 'map' and
|
||||||
|
'greeting'.
|
||||||
|
-}
|
||||||
|
friends :: [String]
|
||||||
|
friends =
|
||||||
|
[ "Peter"
|
||||||
|
, "Nina"
|
||||||
|
, "Janosh"
|
||||||
|
, "Reto"
|
||||||
|
, "Adal"
|
||||||
|
, "Sara"
|
||||||
|
]
|
||||||
|
|
||||||
|
greeting :: String -> String
|
||||||
|
greeting person = "Hello " ++ person
|
||||||
|
|
||||||
|
greetFriends :: [String]
|
||||||
|
greetFriends = map greeting friends
|
||||||
|
|
206
Exercises/exercise-1/Code/B_FunctionsTodo.hs
Normal file
206
Exercises/exercise-1/Code/B_FunctionsTodo.hs
Normal file
|
@ -0,0 +1,206 @@
|
||||||
|
{- Contents
|
||||||
|
A short integerroduction to Haskell;
|
||||||
|
On how to create simple functions.
|
||||||
|
-}
|
||||||
|
|
||||||
|
-----------------------------------------------------------
|
||||||
|
-- Elementary Functions
|
||||||
|
-----------------------------------------------------------
|
||||||
|
|
||||||
|
{- General Syntax for functions
|
||||||
|
* Input on the left, output on the right.
|
||||||
|
* Functions also have a type: input type on the left
|
||||||
|
side, output type on the right side, arrow inbetween.
|
||||||
|
-}
|
||||||
|
inc1 :: Integer -> Integer
|
||||||
|
inc1 n = n + 1
|
||||||
|
|
||||||
|
{- Lambda notation
|
||||||
|
Everything can also be written on the right side (lambda
|
||||||
|
notation). In fact, `inc1` is just syntactic sugar for
|
||||||
|
`inc2`.
|
||||||
|
-}
|
||||||
|
inc2 :: Integer -> Integer
|
||||||
|
inc2 = \n -> n + 1
|
||||||
|
|
||||||
|
{- Function application
|
||||||
|
To apply a function, write the function to the left of
|
||||||
|
the input/argument (no brackets needed).
|
||||||
|
-}
|
||||||
|
two :: Integer
|
||||||
|
two = inc1 1
|
||||||
|
|
||||||
|
someGreeting :: String -> String
|
||||||
|
someGreeting person = "Hello " ++ person
|
||||||
|
|
||||||
|
|
||||||
|
{- Exercise
|
||||||
|
Define a function `square`, that squares the given input
|
||||||
|
and write down its type. Define the same function using
|
||||||
|
the lambda notation.
|
||||||
|
-}
|
||||||
|
square :: Integer -> Integer
|
||||||
|
square x = error "fixme"
|
||||||
|
|
||||||
|
squareLambda :: Integer -> Integer
|
||||||
|
squareLambda = error "fixme"
|
||||||
|
|
||||||
|
|
||||||
|
-----------------------------------------------------------
|
||||||
|
-- Functions of Several Variables
|
||||||
|
-----------------------------------------------------------
|
||||||
|
|
||||||
|
{- Tupled Inputs
|
||||||
|
'addTupled' is binary function, its output depends on
|
||||||
|
two separate integers.
|
||||||
|
-}
|
||||||
|
addTupled :: (Integer, Integer) -> Integer
|
||||||
|
addTupled (x, y) = x + y
|
||||||
|
|
||||||
|
{-
|
||||||
|
'avg3Tupled' is a function that depends on three input
|
||||||
|
variables.
|
||||||
|
-}
|
||||||
|
avg3Tupled :: (Float, Float, Float) -> Float
|
||||||
|
avg3Tupled ( x, y, z ) = (x + y + z) / 3
|
||||||
|
|
||||||
|
{- Evaluating with Tuples
|
||||||
|
We evaluate a function of several variables by providing
|
||||||
|
values *for each* input variabele.
|
||||||
|
-}
|
||||||
|
four :: Float
|
||||||
|
four = avg3Tupled ( 3, 4, 5 )
|
||||||
|
|
||||||
|
{-
|
||||||
|
If we want to evaluate a multivariable function before
|
||||||
|
we have all inputs ready, we have to properly
|
||||||
|
parametrize it. We can do this with curried functions.
|
||||||
|
More on that later!
|
||||||
|
-}
|
||||||
|
|
||||||
|
|
||||||
|
{- A Curried Function
|
||||||
|
'add' is the parametrized (a.k.a curried) version of
|
||||||
|
`add`. It is a function that returns a (unary) function.
|
||||||
|
|
||||||
|
Note that the following three lines are equivalent
|
||||||
|
declarations:
|
||||||
|
|
||||||
|
'add = \x -> \y -> x + y'
|
||||||
|
|
||||||
|
'add x = \y -> x + y'
|
||||||
|
|
||||||
|
'add x y = x + y'
|
||||||
|
|
||||||
|
Also note that the parenthesis are not needed in the
|
||||||
|
declaration of the type of 'add'.
|
||||||
|
-}
|
||||||
|
add :: Int -> (Int -> Int)
|
||||||
|
add n m = n + m
|
||||||
|
|
||||||
|
|
||||||
|
{- Partial Application
|
||||||
|
'add3' is the function that adds '3' to any given input.
|
||||||
|
Thanks to currying, we can realize 'add3' as a special
|
||||||
|
case of 'add'. Thanks to partial application, this
|
||||||
|
corresponds to a single function call.
|
||||||
|
-}
|
||||||
|
add3 :: Int -> Int
|
||||||
|
add3 = add 3
|
||||||
|
|
||||||
|
{- Exercise
|
||||||
|
Declare a curried version of the function 'avg3Tupled'
|
||||||
|
as a lambda term.
|
||||||
|
-}
|
||||||
|
avg3 :: Float -> Float -> Float -> Float
|
||||||
|
avg3 = error "fixme"
|
||||||
|
|
||||||
|
{- Exercise
|
||||||
|
use the binary function '(++)' that concatenates strings
|
||||||
|
to specify a function that prepends "=> " to any given
|
||||||
|
input string. Use partial application
|
||||||
|
-}
|
||||||
|
prepArrow :: String -> String
|
||||||
|
prepArrow = error "fixme"
|
||||||
|
|
||||||
|
-- When calling this
|
||||||
|
-- > prepArrow "foo"
|
||||||
|
-- It should output the following
|
||||||
|
-- '=> foo'
|
||||||
|
|
||||||
|
|
||||||
|
-----------------------------------------------------------
|
||||||
|
-- Higher Order Functions
|
||||||
|
-----------------------------------------------------------
|
||||||
|
|
||||||
|
{- Function as Input
|
||||||
|
'apply' is a function that accepts a function as input
|
||||||
|
(and applies it to the remaining input)
|
||||||
|
-}
|
||||||
|
apply :: (a -> b) -> a -> b
|
||||||
|
apply f x = f x
|
||||||
|
|
||||||
|
{- Function as Input and Output
|
||||||
|
'twice' is a function that accepts and returns a
|
||||||
|
function.
|
||||||
|
-}
|
||||||
|
twice :: (a -> a) -> (a -> a)
|
||||||
|
twice f x = f (f x)
|
||||||
|
-- twice f = f . f -- Alternatively use this syntax
|
||||||
|
|
||||||
|
{- Exercise
|
||||||
|
Write a function `thrice` that applies a function three
|
||||||
|
times.
|
||||||
|
-}
|
||||||
|
thrice :: (a -> a) -> a -> a
|
||||||
|
thrice f x = error "fixme"
|
||||||
|
|
||||||
|
{- Exercise
|
||||||
|
Write a function 'compose' that accepts two functions
|
||||||
|
and applies them to a given argument in order.
|
||||||
|
-}
|
||||||
|
compose :: (a -> b) -> (b -> c) -> a -> c
|
||||||
|
compose f g x = error "fixme"
|
||||||
|
|
||||||
|
{- Exercise
|
||||||
|
reimplement 'twice' and 'thrice' with as an application
|
||||||
|
of the function 'compose'.
|
||||||
|
-}
|
||||||
|
twiceByComp :: (a -> a) -> a -> a
|
||||||
|
twiceByComp f = error "fixme"
|
||||||
|
|
||||||
|
thriceByComp :: (a -> a) -> a -> a
|
||||||
|
thriceByComp f = error "fixme"
|
||||||
|
|
||||||
|
{- List map
|
||||||
|
A often used higher function is ``mapping'' of lists.
|
||||||
|
This function will apply a function (given as an
|
||||||
|
argument) to every element in a list (also given as an
|
||||||
|
argument) and return a new list containig the changed
|
||||||
|
values. There are a lot of other functions to work
|
||||||
|
with lists (and similar types). We will learn about
|
||||||
|
these functions later.
|
||||||
|
-}
|
||||||
|
mapping :: [Integer]
|
||||||
|
mapping = map (\n -> n + 1) [1, 2, 3]
|
||||||
|
|
||||||
|
{-| Exercise
|
||||||
|
greet all friends using 'friends', 'map' and
|
||||||
|
'greeting'.
|
||||||
|
-}
|
||||||
|
friends :: [String]
|
||||||
|
friends =
|
||||||
|
[ "Peter"
|
||||||
|
, "Nina"
|
||||||
|
, "Janosh"
|
||||||
|
, "Reto"
|
||||||
|
, "Adal"
|
||||||
|
, "Sara"
|
||||||
|
]
|
||||||
|
|
||||||
|
greeting :: String -> String
|
||||||
|
greeting person = "Hello " ++ person
|
||||||
|
|
||||||
|
greetFriends :: [String]
|
||||||
|
greetFriends = error "fixme"
|
||||||
|
|
148
Exercises/exercise-1/Code/C_Types.hs
Normal file
148
Exercises/exercise-1/Code/C_Types.hs
Normal file
|
@ -0,0 +1,148 @@
|
||||||
|
{- Contents
|
||||||
|
A short introduction to Haskell;
|
||||||
|
On how to create your own types
|
||||||
|
-}
|
||||||
|
|
||||||
|
{- Preliminary Remark
|
||||||
|
There are several different Keywords to declare new
|
||||||
|
types ('data', 'newtype', 'type'). We will discuss the
|
||||||
|
difference of these keywords and when to use
|
||||||
|
which later.
|
||||||
|
-}
|
||||||
|
|
||||||
|
-----------------------------------------------------------
|
||||||
|
-- Product Types
|
||||||
|
-----------------------------------------------------------
|
||||||
|
|
||||||
|
{- Records
|
||||||
|
Records are tuples with custom named fields and a
|
||||||
|
constructor.
|
||||||
|
-}
|
||||||
|
data Character = Character
|
||||||
|
{ firstName :: String
|
||||||
|
, lastName :: String
|
||||||
|
}
|
||||||
|
|
||||||
|
han :: Character
|
||||||
|
han = Character
|
||||||
|
{ firstName = "Han"
|
||||||
|
, lastName = "Solo"
|
||||||
|
}
|
||||||
|
|
||||||
|
obiWan :: Character
|
||||||
|
obiWan = Character
|
||||||
|
{ firstName = "Obi-Wan"
|
||||||
|
, lastName = "Kenobi"
|
||||||
|
}
|
||||||
|
|
||||||
|
{- "Getters"
|
||||||
|
Values can be extracted from records by using the fields
|
||||||
|
name as a function.
|
||||||
|
-}
|
||||||
|
solo :: String
|
||||||
|
solo = firstName han
|
||||||
|
|
||||||
|
kenobi :: String
|
||||||
|
kenobi = lastName obiWan
|
||||||
|
|
||||||
|
{- 'first' and 'last' can be used like any other function.
|
||||||
|
-}
|
||||||
|
firstNames :: [String]
|
||||||
|
firstNames = map firstName [ han, obiWan ]
|
||||||
|
|
||||||
|
{- Exercise
|
||||||
|
Greet Obi-Wan and Han, each with a phrase like e.g.
|
||||||
|
"Hello Obi-Wan". Use 'map' and 'first'.
|
||||||
|
-}
|
||||||
|
greetings :: [String]
|
||||||
|
greetings = map (("Hello " ++) . firstName) [ han, obiWan ]
|
||||||
|
|
||||||
|
{- "Setters"
|
||||||
|
Values of a record can be changed with the syntax below.
|
||||||
|
What is important to note here is that 'han' will not be
|
||||||
|
changed. A copy of 'han' will be made with the first
|
||||||
|
name changed.
|
||||||
|
-}
|
||||||
|
ben :: Character
|
||||||
|
ben = han {firstName = "Ben"}
|
||||||
|
|
||||||
|
|
||||||
|
-----------------------------------------------------------
|
||||||
|
-- Sum Types
|
||||||
|
-----------------------------------------------------------
|
||||||
|
|
||||||
|
{- Sum Types
|
||||||
|
The values of a sum type come in a number of different
|
||||||
|
variants. Each value can be uniquely assigned to one of
|
||||||
|
the variants.
|
||||||
|
Our first sum type contains exactly two values. This
|
||||||
|
type is isomorphic to 'Bool'.
|
||||||
|
-}
|
||||||
|
data YesNo
|
||||||
|
= Yes
|
||||||
|
| No
|
||||||
|
|
||||||
|
yes :: YesNo
|
||||||
|
yes = Yes
|
||||||
|
|
||||||
|
{- The following types look similar to the type above, but
|
||||||
|
they contain values in the options.
|
||||||
|
-}
|
||||||
|
data Identification
|
||||||
|
= Email String
|
||||||
|
| Username String
|
||||||
|
|
||||||
|
hanId :: Identification
|
||||||
|
hanId = Username "han_32"
|
||||||
|
|
||||||
|
obiWanId :: Identification
|
||||||
|
obiWanId = Email "kenobi@rebel-alliance.space"
|
||||||
|
|
||||||
|
{- Recursive Types
|
||||||
|
A cool fact about union types is that they can be
|
||||||
|
recursive. The standard example is that of binary trees.
|
||||||
|
-}
|
||||||
|
data BinaryTree a
|
||||||
|
= Node a (BinaryTree a) (BinaryTree a)
|
||||||
|
| Leaf a
|
||||||
|
|
||||||
|
{-
|
||||||
|
A simple binary tree with integers.
|
||||||
|
-}
|
||||||
|
tree :: BinaryTree Int
|
||||||
|
tree = Node 1 (Leaf 2) (Leaf 3)
|
||||||
|
|
||||||
|
{- Lists are also a recursive sum type (with syntactic sugar
|
||||||
|
for 'Cons' and 'E')
|
||||||
|
-}
|
||||||
|
data MyList a
|
||||||
|
= Cons a (MyList a)
|
||||||
|
| Nil
|
||||||
|
|
||||||
|
{-
|
||||||
|
[1,2,3] as 'MyList'
|
||||||
|
-}
|
||||||
|
list :: MyList Integer
|
||||||
|
list =
|
||||||
|
Cons
|
||||||
|
1
|
||||||
|
(Cons
|
||||||
|
2
|
||||||
|
(Cons
|
||||||
|
3
|
||||||
|
Nil
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
{- Combining Unions and Records
|
||||||
|
It is possible to "inline" records in cases of union
|
||||||
|
types.
|
||||||
|
-}
|
||||||
|
|
||||||
|
data Shape
|
||||||
|
= Circle { radius :: Float }
|
||||||
|
| Rectangle
|
||||||
|
{ len :: Float
|
||||||
|
, width :: Float
|
||||||
|
}
|
||||||
|
|
149
Exercises/exercise-1/Code/C_TypesTodo.hs
Normal file
149
Exercises/exercise-1/Code/C_TypesTodo.hs
Normal file
|
@ -0,0 +1,149 @@
|
||||||
|
{- Contents
|
||||||
|
A short introduction to Haskell;
|
||||||
|
On how to create your own types
|
||||||
|
-}
|
||||||
|
|
||||||
|
{- Preliminary Remark
|
||||||
|
There are several different Keywords to declare new
|
||||||
|
types ('data', 'newtype', 'type'). We will discuss the
|
||||||
|
difference of these keywords and when to use
|
||||||
|
which later.
|
||||||
|
-}
|
||||||
|
|
||||||
|
-----------------------------------------------------------
|
||||||
|
-- Product Types
|
||||||
|
-----------------------------------------------------------
|
||||||
|
|
||||||
|
{- Records
|
||||||
|
Records are tuples with custom named fields and a
|
||||||
|
constructor.
|
||||||
|
-}
|
||||||
|
data Character = Character
|
||||||
|
{ firstName :: String
|
||||||
|
, lastName:: String
|
||||||
|
}
|
||||||
|
|
||||||
|
han :: Character
|
||||||
|
han = Character
|
||||||
|
{ firstName = "Han"
|
||||||
|
, lastName = "Solo"
|
||||||
|
}
|
||||||
|
|
||||||
|
obiWan :: Character
|
||||||
|
obiWan = Character
|
||||||
|
{ firstName = "Obi-Wan"
|
||||||
|
, lastName = "Kenobi"
|
||||||
|
}
|
||||||
|
|
||||||
|
{- "Getters"
|
||||||
|
Values can be extracted from records by using the fields
|
||||||
|
name as a function.
|
||||||
|
firstName :: Character -> String
|
||||||
|
age :: Character -> Integer
|
||||||
|
-}
|
||||||
|
solo :: String
|
||||||
|
solo = firstName han
|
||||||
|
|
||||||
|
kenobi :: String
|
||||||
|
kenobi = lastName obiWan
|
||||||
|
|
||||||
|
{- 'first' and 'last' can be used like any other function.
|
||||||
|
-}
|
||||||
|
firstNames :: [String]
|
||||||
|
firstNames = map firstName [ han, obiWan ]
|
||||||
|
|
||||||
|
{- Exercise
|
||||||
|
Greet Obi-Wan and Han, each with a phrase like e.g.
|
||||||
|
"Hello Obi-Wan". Use 'map' and 'first'.
|
||||||
|
-}
|
||||||
|
greetings :: [String]
|
||||||
|
greetings = error "fixme"
|
||||||
|
|
||||||
|
{- "Setters"
|
||||||
|
Values of a record can be changed with the syntax below.
|
||||||
|
What is important to note here is that 'han' will not be
|
||||||
|
changed. A copy of 'han' will be made with the first
|
||||||
|
name changed.
|
||||||
|
-}
|
||||||
|
ben :: Character
|
||||||
|
ben = han {firstName = "Ben"}
|
||||||
|
|
||||||
|
|
||||||
|
-----------------------------------------------------------
|
||||||
|
-- Sum Types
|
||||||
|
-----------------------------------------------------------
|
||||||
|
|
||||||
|
{- Sum Types
|
||||||
|
The values of a sum type come in a number of different
|
||||||
|
variants. Each value can be uniquely assigned to one of
|
||||||
|
the variants.
|
||||||
|
Our first sum type contains exactly two values. This
|
||||||
|
type is isomorphic to 'Bool'.
|
||||||
|
-}
|
||||||
|
data YesNo
|
||||||
|
= Yes -- Constructors
|
||||||
|
| No
|
||||||
|
|
||||||
|
yes :: YesNo
|
||||||
|
yes = Yes
|
||||||
|
|
||||||
|
{- The following types look similar to the type above, but
|
||||||
|
they contain values in the options.
|
||||||
|
-}
|
||||||
|
data Identification
|
||||||
|
= Email String
|
||||||
|
| Username String
|
||||||
|
|
||||||
|
hanId :: Identification
|
||||||
|
hanId = Username "han_32"
|
||||||
|
|
||||||
|
obiWanId :: Identification
|
||||||
|
obiWanId = Email "kenobi@rebel-alliance.space"
|
||||||
|
|
||||||
|
{- Recursive Types
|
||||||
|
A cool fact about union types is that they can be
|
||||||
|
recursive. The standard example is that of binary trees.
|
||||||
|
-}
|
||||||
|
data BinaryTree a
|
||||||
|
= Node a (BinaryTree a) (BinaryTree a)
|
||||||
|
| Leaf a
|
||||||
|
|
||||||
|
{-
|
||||||
|
A simple binary tree with integers.
|
||||||
|
-}
|
||||||
|
tree :: BinaryTree Int
|
||||||
|
tree = Node 1 (Leaf 2) (Leaf 3)
|
||||||
|
|
||||||
|
{- Lists are also a recursive sum type (with syntactic sugar
|
||||||
|
for 'Cons' and 'E')
|
||||||
|
-}
|
||||||
|
data MyList a
|
||||||
|
= Cons a (MyList a)
|
||||||
|
| Nil
|
||||||
|
|
||||||
|
{-
|
||||||
|
[1,2,3] as 'MyList'
|
||||||
|
-}
|
||||||
|
list :: MyList Integer
|
||||||
|
list =
|
||||||
|
Cons
|
||||||
|
1
|
||||||
|
(Cons
|
||||||
|
2
|
||||||
|
(Cons
|
||||||
|
3
|
||||||
|
Nil
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
{- Combining Unions and Records
|
||||||
|
It is possible to "inline" records in cases of union
|
||||||
|
types.
|
||||||
|
-}
|
||||||
|
data Shape
|
||||||
|
= Circle { radius :: Float }
|
||||||
|
| Rectangle
|
||||||
|
{ len :: Float
|
||||||
|
, width :: Float
|
||||||
|
}
|
||||||
|
|
168
Exercises/exercise-1/Code/D_Control.hs
Normal file
168
Exercises/exercise-1/Code/D_Control.hs
Normal file
|
@ -0,0 +1,168 @@
|
||||||
|
-----------------------------------------------------------
|
||||||
|
-- If Else and Guards
|
||||||
|
-----------------------------------------------------------
|
||||||
|
|
||||||
|
{- IfElse
|
||||||
|
* If-else expressions denote "normal" values
|
||||||
|
-}
|
||||||
|
three :: Integer
|
||||||
|
three = if True then 3 else 4
|
||||||
|
|
||||||
|
four :: Integer
|
||||||
|
four = if False then 0 else 4
|
||||||
|
|
||||||
|
collatzNext :: Integer -> Integer
|
||||||
|
collatzNext x =
|
||||||
|
if x `mod` 2 == 0 then
|
||||||
|
x `div` 2
|
||||||
|
else
|
||||||
|
3*x+1
|
||||||
|
|
||||||
|
{- Nesting
|
||||||
|
If-else expressions with multiple cases are possible
|
||||||
|
with nesting.
|
||||||
|
-}
|
||||||
|
describe :: Integer -> String
|
||||||
|
describe x =
|
||||||
|
if x < 3 then
|
||||||
|
"small"
|
||||||
|
else if x < 5 then
|
||||||
|
"medium"
|
||||||
|
else
|
||||||
|
"large"
|
||||||
|
|
||||||
|
{- Guards
|
||||||
|
An alternative way to declare functions by case analysis
|
||||||
|
are guards.
|
||||||
|
-}
|
||||||
|
describe' :: Integer -> String
|
||||||
|
describe' x -- First match wins
|
||||||
|
| x < 3 = "small"
|
||||||
|
| x < 4 = "medium"
|
||||||
|
| otherwise = "large"
|
||||||
|
|
||||||
|
sign :: Integer -> Integer
|
||||||
|
sign x
|
||||||
|
| x < 0 = -1
|
||||||
|
| x > 0 = 1
|
||||||
|
| otherwise = 0
|
||||||
|
|
||||||
|
{- Exercise
|
||||||
|
rewrite the function 'fIfElse' using guards.
|
||||||
|
-}
|
||||||
|
fIfElse :: Integer -> String
|
||||||
|
fIfElse n =
|
||||||
|
if n `mod` 2 == 1 then
|
||||||
|
if n `mod` 3 /= 0 then
|
||||||
|
"Oddity"
|
||||||
|
else
|
||||||
|
"Odd"
|
||||||
|
else
|
||||||
|
"Even"
|
||||||
|
|
||||||
|
fGuard :: Integer -> String
|
||||||
|
fGuard n
|
||||||
|
| n `mod` 2 == 0 = "Even"
|
||||||
|
| n `mod` 3 == 0 = "Odd"
|
||||||
|
| otherwise = "Oddity"
|
||||||
|
|
||||||
|
-----------------------------------------------------------
|
||||||
|
-- Cases and pattern matching
|
||||||
|
-----------------------------------------------------------
|
||||||
|
|
||||||
|
{- Cases 1
|
||||||
|
Aside from if-else and guards, Haskell also allows for
|
||||||
|
functions to be declared in separate clauses.
|
||||||
|
-}
|
||||||
|
|
||||||
|
count :: Integer -> String
|
||||||
|
count 0 = "zero"
|
||||||
|
count 1 = "one"
|
||||||
|
count 2 = "two"
|
||||||
|
count _ = "I don't know"
|
||||||
|
|
||||||
|
{- Cases 2
|
||||||
|
There is also an alternative syntax for cases (that make
|
||||||
|
declarations a bit easier to maintain in some cases).
|
||||||
|
-}
|
||||||
|
|
||||||
|
count' :: Integer -> String
|
||||||
|
count' n = case n of
|
||||||
|
0 -> "zero"
|
||||||
|
1 -> "one"
|
||||||
|
2 -> "two"
|
||||||
|
_ -> "I don't know"
|
||||||
|
|
||||||
|
|
||||||
|
{- Cases Importance
|
||||||
|
The true "power" of cases is in conjunction with custom
|
||||||
|
types and pattern matching. We will learn how this works
|
||||||
|
later.
|
||||||
|
-}
|
||||||
|
|
||||||
|
data Shape
|
||||||
|
= Rectangle Float Float
|
||||||
|
| Circle Float
|
||||||
|
|
||||||
|
circumference :: Shape -> Float
|
||||||
|
circumference shape = case shape of
|
||||||
|
Rectangle length width ->
|
||||||
|
2*length + 2*width
|
||||||
|
Circle radius ->
|
||||||
|
2*radius*pi
|
||||||
|
|
||||||
|
{- Exercise
|
||||||
|
Define a function
|
||||||
|
'area :: Shape -> Float'
|
||||||
|
to compute the area of any given shape. Use spearate
|
||||||
|
cases such as in 'Case 1' above.
|
||||||
|
-}
|
||||||
|
area :: Shape -> Float
|
||||||
|
area (Rectangle l w) = l*w
|
||||||
|
area (Circle r) = r*r*pi
|
||||||
|
|
||||||
|
|
||||||
|
-----------------------------------------------------------
|
||||||
|
-- Let and where
|
||||||
|
-----------------------------------------------------------
|
||||||
|
|
||||||
|
{- Let Bindings
|
||||||
|
It is possible to name one or more values in a
|
||||||
|
"let-block" and these abbreviations in the subsequent
|
||||||
|
expression.
|
||||||
|
-}
|
||||||
|
five :: Integer
|
||||||
|
five =
|
||||||
|
let
|
||||||
|
x = 2
|
||||||
|
y = x + 1
|
||||||
|
in
|
||||||
|
x + y
|
||||||
|
|
||||||
|
myFunc :: Integer -> Integer
|
||||||
|
myFunc x =
|
||||||
|
let
|
||||||
|
complicated =
|
||||||
|
x `mod` 2 == 0 && x `mod` 4 /= 0
|
||||||
|
in
|
||||||
|
if complicated then
|
||||||
|
x `div` 2
|
||||||
|
else
|
||||||
|
x + 1
|
||||||
|
|
||||||
|
{- Where
|
||||||
|
Where is the same as let, but it does not preceed but
|
||||||
|
follow a "main" declaration.
|
||||||
|
-}
|
||||||
|
six :: Integer
|
||||||
|
six =
|
||||||
|
x + y
|
||||||
|
where
|
||||||
|
x = 2
|
||||||
|
y = x + 2
|
||||||
|
|
||||||
|
myFunc' :: Integer -> Integer
|
||||||
|
myFunc' x =
|
||||||
|
(magicNumber * x) + 1
|
||||||
|
where
|
||||||
|
magicNumber = x + 42
|
166
Exercises/exercise-1/Code/D_ControlTodo.hs
Normal file
166
Exercises/exercise-1/Code/D_ControlTodo.hs
Normal file
|
@ -0,0 +1,166 @@
|
||||||
|
-----------------------------------------------------------
|
||||||
|
-- If Else and Guards
|
||||||
|
-----------------------------------------------------------
|
||||||
|
|
||||||
|
{- IfElse
|
||||||
|
* If-else expressions denote "normal" values
|
||||||
|
-}
|
||||||
|
three :: Integer
|
||||||
|
three = if True then 3 else 4
|
||||||
|
|
||||||
|
four :: Integer
|
||||||
|
four = if False then 0 else 4
|
||||||
|
|
||||||
|
collatzNext :: Integer -> Integer
|
||||||
|
collatzNext x =
|
||||||
|
if x `mod` 2 == 0 then
|
||||||
|
x `div` 2
|
||||||
|
else
|
||||||
|
3*x+1
|
||||||
|
|
||||||
|
{- Nesting
|
||||||
|
If-else expressions with multiple cases are possible
|
||||||
|
with nesting.
|
||||||
|
-}
|
||||||
|
describe :: Integer -> String
|
||||||
|
describe x =
|
||||||
|
if x < 3 then
|
||||||
|
"small"
|
||||||
|
else if x < 5 then
|
||||||
|
"medium"
|
||||||
|
else
|
||||||
|
"large"
|
||||||
|
|
||||||
|
{- Guards
|
||||||
|
An alternative way to declare functions by case analysis
|
||||||
|
are guards.
|
||||||
|
-}
|
||||||
|
describe' :: Integer -> String
|
||||||
|
describe' x
|
||||||
|
| x < 3 = "small"
|
||||||
|
| x < 4 = "medium"
|
||||||
|
| otherwise = "large"
|
||||||
|
|
||||||
|
sign :: Integer -> Integer
|
||||||
|
sign x
|
||||||
|
| x < 0 = -1
|
||||||
|
| x > 0 = 1
|
||||||
|
| otherwise = 0
|
||||||
|
|
||||||
|
{- Exercise
|
||||||
|
rewrite the function 'fIfElse' using guards.
|
||||||
|
-}
|
||||||
|
fIfElse :: Integer -> String
|
||||||
|
fIfElse n =
|
||||||
|
if n `mod` 2 == 1 then
|
||||||
|
if n `mod` 3 /= 0 then
|
||||||
|
"Oddity"
|
||||||
|
else
|
||||||
|
"Odd"
|
||||||
|
else
|
||||||
|
"Even"
|
||||||
|
|
||||||
|
|
||||||
|
fGuard :: Integer -> String
|
||||||
|
fGuard = error "fixme"
|
||||||
|
|
||||||
|
|
||||||
|
-----------------------------------------------------------
|
||||||
|
-- Cases and pattern matching
|
||||||
|
-----------------------------------------------------------
|
||||||
|
|
||||||
|
{- Cases 1
|
||||||
|
Aside from if-else and guards, Haskell also allows for
|
||||||
|
functions to be declared in separate clauses.
|
||||||
|
-}
|
||||||
|
|
||||||
|
count :: Integer -> String
|
||||||
|
count 0 = "zero"
|
||||||
|
count 1 = "one"
|
||||||
|
count 2 = "two"
|
||||||
|
count _ = "I don't know"
|
||||||
|
|
||||||
|
{- Cases 2
|
||||||
|
There is also an alternative syntax for cases (that make
|
||||||
|
declarations a bit easier to maintain in some cases).
|
||||||
|
-}
|
||||||
|
|
||||||
|
count' :: Integer -> String
|
||||||
|
count' n = case n of
|
||||||
|
0 -> "zero"
|
||||||
|
1 -> "one"
|
||||||
|
2 -> "two"
|
||||||
|
_ -> "I don't know"
|
||||||
|
|
||||||
|
|
||||||
|
{- Cases Importance
|
||||||
|
The true "power" of cases is in conjunction with custom
|
||||||
|
types and pattern matching. We will learn how this works
|
||||||
|
later.
|
||||||
|
-}
|
||||||
|
|
||||||
|
data Shape
|
||||||
|
= Rectangle Float Float
|
||||||
|
| Circle Float
|
||||||
|
|
||||||
|
circumference :: Shape -> Float
|
||||||
|
circumference shape = case shape of
|
||||||
|
Rectangle length width ->
|
||||||
|
2*length + 2*width
|
||||||
|
Circle radius ->
|
||||||
|
2*radius*pi
|
||||||
|
|
||||||
|
{- Exercise
|
||||||
|
Define a function
|
||||||
|
'area :: Shape -> Float'
|
||||||
|
to compute the area of any given shape. Use spearate
|
||||||
|
cases such as in 'Case 1' above.
|
||||||
|
-}
|
||||||
|
area :: Shape -> Float
|
||||||
|
area = error "fixme"
|
||||||
|
|
||||||
|
|
||||||
|
-----------------------------------------------------------
|
||||||
|
-- Let and where
|
||||||
|
-----------------------------------------------------------
|
||||||
|
|
||||||
|
{- Let Bindings
|
||||||
|
It is possible to name one or more values in a
|
||||||
|
"let-block" and these abbreviations in the subsequent
|
||||||
|
expression.
|
||||||
|
-}
|
||||||
|
five :: Integer
|
||||||
|
five =
|
||||||
|
let
|
||||||
|
x = 2
|
||||||
|
y = x + 1
|
||||||
|
in
|
||||||
|
x + y
|
||||||
|
|
||||||
|
myFunc :: Integer -> Integer
|
||||||
|
myFunc x =
|
||||||
|
let
|
||||||
|
complicated =
|
||||||
|
x `mod` 2 == 0 && x `mod` 4 /= 0
|
||||||
|
in
|
||||||
|
if complicated then
|
||||||
|
x `div` 2
|
||||||
|
else
|
||||||
|
x + 1
|
||||||
|
|
||||||
|
{- Where
|
||||||
|
Where is the same as let, but it does not preceed but
|
||||||
|
follow a "main" declaration.
|
||||||
|
-}
|
||||||
|
six :: Integer
|
||||||
|
six =
|
||||||
|
x + y
|
||||||
|
where
|
||||||
|
x = 2
|
||||||
|
y = x + 2
|
||||||
|
|
||||||
|
myFunc' :: Integer -> Integer
|
||||||
|
myFunc' x =
|
||||||
|
(magicNumber * x) + 1
|
||||||
|
where
|
||||||
|
magicNumber = x + 42
|
Loading…
Reference in a new issue