Functional programming
About me
- 2nd year Software Science
- High tech systems track
- President AEGEE-Eindhoven

Things I ♥
- Travelling
- Learning
- Food
- (functional) programming
- Kabouter Wesley


Today's project
avg-grade
- Displays average grade according to Canvas
- (Gives either advice or compliment)
Structure
- Display average grade according to Canvas
- Give either advice or compliment
- Input
- Transformation
- Output
- Get grades from Canvas
- Calculate average
- Display average, advice/compliment
"Pipeline"
Web server
- Input
- Transformation
- Output
- Receive URL request, database
- Generate page
- Send page
Real life example
Transformation
- Calculate the output,
- based on a rule,
- from the input
f(x) = x + 1
f(x)=x+1
e.g. output = input + 1
Sounds familiar?
Math →
f :: Integer -> Integer
f x = x + 1
f(x) = x + 1
f(x)=x+1
Math →
add :: Integer -> Integer -> Integer
add x y = x + y
add(x, y) = x + y
add(x,y)=x+y
add :: Integer, Integer -> Integer
add x y = x + y

Types

add :: Integer -> Integer -> Integer
add x y = x + y
-- We can use add like so:
add 1 2 -- output: 3
-- But also like this:
(add 1) 2 -- output: 3
-- The type of (add 1) is: Integer -> Integer
f : Integer -> Integer
f = add 1
-- Instead of f x = x + 1Partial application
Given \(add(x,y) = x + y\), what does \(add(x)\) mean?
- Definition: \(add(x, y) = add(x)(y)\)
- Corollary: \(add(x)\) returns a function
- \(f(x) = add (1)(x)\), so \(f = add(1)\)
"Currying"
Types
2 :: Integer
3.14 :: Float
'a' :: Char
[0, 1, 2, 3, 4, 5] :: [Integer]
['D', 'a', 'a', 'n'] :: [Char]
type String = [Char] -- Defines alias
"Hello, Confluente!" :: String
data Degree -- Defines a new data type
= Bachelor
| Master
| PhD
data Person -- Defines a new record type
= Person {
name :: String,
age :: Integer,
degree :: Degree
}
-- Use like this:
Person {
name = "Daan de Graaf",
age = 19,
degree = Bachelor
} :: Person
-- This automatically defines:
name :: Person -> String
age :: Person -> Integer
degree :: Person -> DegreeTypes
-- Container that may or may not be empty
data Maybe a
= Just a
| Nothing
-- Use like this:
Just 3 :: Maybe Integer
Nothing :: Maybe Integer
-- Useful when return value is undefined for some input
sqrt :: Float -> Float
sqrt 9 -- 3
sqrt -1 -- ?
-- Better:
sqrt :: Float -> Maybe Float
sqrt 9 -- Just 3
sqrt -1 -- NothingParametric types
Input
Output
Types
type Grade = Float
data Course
= Course {
id :: Integer,
name :: String,
grade :: Maybe Grade
}type Average = Floattransform :: [Course] -> Average
-- We need to implement this functionTransformation
Transform implementation
[Course]
[Maybe Grade]
[Grade]
Float
Integer
Average
Transform implementation
Mapping
-- Easy for a single Course:
grade :: Course -> Maybe Grade
-- But we need:
grades :: [Course] -> [Maybe Grade]
-- For different apps we also need:
ids :: [Course] -> [Integer]
names :: [Course] -> [String]
-- General pattern?map :: (a -> b) -> [a] -> [b]
-- Substitute Course for a, Maybe Grade for b
map :: (Course -> Maybe Grade) -> [Course] -> [Maybe Grade]
grades :: [Course] -> [Maybe Grade]
grades = map gradeTransform implementation
Hoogle to the rescue
-- We need:
magic :: [Maybe Grade] -> [Grade]Extracting 'Just' from a list is a common pattern
catMaybes :: [Maybe Grade] -> [Grade]mapMaybe :: (a -> Maybe b) -> [a] -> [b]
mapMaybe grade :: [Course] -> [Grade]Transform implementation
Average
sum(X) = \sum_{k=1}^{n} x_k
sum(X)=∑k=1nxk
X = {x_1, x_2, ..., x_n}
X=x1,x2,...,xn
average(X) = \frac{sum(x_n)}{n}
average(X)=nsum(xn)
type Average = Float
sum :: [Float] -> Float
length :: [a] -> Integer
(/) :: Float -> Float -> Float
average :: [Grade] -> Average
-- This does not work:
average gs = sum gs / length gs-- Luckily we have:
genericLength :: [a] -> Float
-- This works:
average gs = sum gs / genericLength gs- Couldn't match type ‘Integer’ with ‘Float’
- In the second argument of '(/)', namely 'length gs'
Transform implementation
Putting things together
-- Our end goal
transform :: [Course] -> Average
-- We have:
grade :: Course -> Maybe Grade
mapMaybe :: (a -> Maybe b) -> [a] -> [b]
average :: [Grade] -> Averagetransform cs = average . (mapMaybe grade) cs
transform = average . mapMaybe grade(f \circ g) (x) = f(g(x))
(f∘g)(x)=f(g(x))
transform cs = average (mapMaybe grade cs)Transform
is
awesome!
How do we get input to transform?
How do we display transformed output?
Getting things done
-- Haskell evaluates this function at startup
main :: IO ()
main = ...- Return type
IO () - No parameters
- What is
IO a?- Command
- Baton
-- Executing this will yield String
getLine :: IO String
-- Takes a string, yield nothing
putStrLn :: String -> IO ()
-- Example program:
main :: IO ()
main = putStrLn "Hello, world!"
Learning to do
Enter pipeline
- Pipe creation:
IO a - Transform
- Pipe draining:
a -> IO () - Use
donotation to construct a pipeline:
getLines :: IO [String]
reverse :: [a] -> [a]
putStrLns :: [String] -> IO ()
main :: IO ()
main = do
lines <- getLines -- Pipe creation
let reversed = map reverse lines -- Transformation
putStrLns reversed -- Pipe drainingMonad
Learning to do
avg-grade pipeline
getCourses :: IO [Course]
transform :: [Course] -> Average
print :: Average -> IO ()
main :: IO ()
main = do
courses <- getCourses -- Pipe creation
let avg = transform courses -- Transformation
print avg -- Pipe drainingFunctional programming
By wildarch
Functional programming
- 374
