zhaw-fup/Exercises/exercise-1/Code/B_Functions.hs

203 lines
5 KiB
Haskell
Raw Normal View History

2024-03-14 13:59:07 +00:00
{- Contents
2024-03-14 17:02:18 +00:00
A short introduction to Haskell;
2024-03-14 13:59:07 +00:00
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
2024-03-14 17:02:18 +00:00
side, output type on the right side, arrow in-between.
2024-03-14 13:59:07 +00:00
-}
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
2024-03-14 17:02:18 +00:00
values *for each* input variable.
2024-03-14 13:59:07 +00:00
-}
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
2024-03-14 17:02:18 +00:00
reimplement 'twice' and 'thrice' as an application
2024-03-14 13:59:07 +00:00
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
2024-03-14 17:02:18 +00:00
argument) and return a new list containing the changed
2024-03-14 13:59:07 +00:00
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