Add files for lab 01

This commit is contained in:
Manuel Thalmann 2024-03-14 14:59:07 +01:00
parent dffb3bdce3
commit 3bb0b1ead0
8 changed files with 1486 additions and 0 deletions

View 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 ]

View 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"

View 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

View 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"

View 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
}

View 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
}

View 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

View 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