Introduction to Functional Programming
Sébastien BESNIER
initialModel =
{ count = 0 }
type Msg
= Increment
| Decrement
update msg model =
case msg of
Increment ->
{ model | count = model.count + 1 }
Decrement ->
{ model | count = model.count - 1 }
view model =
div [style "font-size" "200%"]
[ button [ onClick Increment ] [ text "+1" ]
, div [ style "color" "red" ] [ text <| String.fromInt model.count ]
, button [ onClick Decrement ] [ text "-1" ]
]
https://ellie-app.com/fDyHsFVJCska1
Challenge: Reset to 0
No mutation! Only values and pure functions
No mutation! Only values and pure functions
Do you know impure functions?
See Elm architecture:
eight = 5 + 3
Affectation
Try it online
eight = round 8.3
Function call
add a b = a + b
Function definition
add a b = a + b
-- call that function:
eight = add 7 1
Function definition
Challenge
Compute length of \(\texttt{"hello world"}\) and add 5 to it using the \(\texttt{add}\) function (in 1 expresion!)
String.length "abc" -- returns 3
eight = add 7 1
add a b = a + b
Order of declarations does not matter
add : Int -> Int -> Int
add a b = a + b
Types
String.length : ???
What is the type of String.length ?
String.length : String -> Int
What is the type of String.length ?
add3 a b c = a + b + c
What is the type of add3?
add3:
Int
-> Int
-> Int
-> Int
add3 a b c = a + b + c
Good practice:
add type anotation!
String.append "hello " "world"
-- returns "hello world"
What is the type of String.append ?
String.append "hello " "world"
-- returns "hello world"
String.append : String -> String -> String
What is the type of String.append ?
t = add 5 String.append "hey" "hoy"
f a b =
String.length (String.append a b)
g a b =
add (String.append a a) b
h a b =
add (String.append a b) b
What is the type of the following expressions?
user =
{ name = "Seb"
, score = 42
, city = "Paris"
}
Records
user : User
user =
{ name = "Seb"
, score = 42
, city = "Paris"
}
Records
type alias User =
{ name : String
, score : Int
, city : String
}
Records
newUser =
{ user | score = 43 }
newUserBis =
{ user | score = user.score + 1 }
Record updates
newUser : User
newUser =
{ user | score = 43 }
newUserBis : User
newUserBis =
{ user | score = user.score + 1 }
Record updates
rewardUser : User -> User
-- increase the score by one
Record updates
rewardUser : User -> User
rewardUser user =
{ user | score = user.score + 1 }
Record updates
Challenge: add type definition for the model in the counter example
Custom types
Records to store multiple data
(name, score, city....)
Custom types
Records to store multiple data
(name, score, city....)
What about data following various patterns ?
Modeling a shape
Point Circle Float Rectangle Float Float
Radius
Length
Width
What is the type of a shape?
Reminder: counter
type Msg
= Increment
| Decrement
First variant
Second variant
Modeling a shape
Point Circle Float Rectangle Float Float
Radius
Length
Width
Modeling a shape
Point Circle Float Rectangle Float Float
Modeling a shape
type Shape =
Point | Circle Float | Rectangle Float Float
Use a custom type
myRect = Rectangle 10 20
bigCircle = Circle 420000
describe : ???
describe shape =
case shape of
Point ->
"A lonely point"
Circle radius ->
"A circle of radius "
++ String.fromFloat radius
Rectangle width height ->
"A rectangle of area "
++ String.fromFloat (width*height)
Use a custom type
myRect = Rectangle 10 20
bigCircle = Circle 420000
describe : Shape -> String
describe shape =
case shape of
Point ->
"A lonely point"
Circle radius ->
"A circle of radius "
++ String.fromFloat radius
Rectangle width height ->
"A rectangle of area "
++ String.fromFloat (width*height)
Boolean
Defined by the language
-- Defined by Elm
type Bool = True | False
-- our code:
myBool = True
res =
case myBool of
True -> 42
False -> 18
Boolean
Defined by the language
-- Defined by Elm
type Bool = True | False
-- our code:
myBool = True
res =
case myBool of
True -> 42
False -> 18
res =
if myBool then
42
else
18
Preferred way:
if(condition) {
myVar = 42;
} else {
myVar = 18;
}
myVar = condition ? 42 : 18;
VS
Conditionals
in imperative language (Java, C, Python...)
Conditionals
in imperative language (Java, C, Python...)
myVar = condition ? 42 : 18;
VS
INSTRUCTION:
changes the state
EXPRESSION:
compute a new value
if(condition) {
myVar = 42;
} else {
myVar = 18;
}
Implement highlight on hover
https://ellie-app.com/fF4BSNrDVK4a1
1st step: define Model & Msg and implement update
A bit of maths
- Custom types are "sum" types
- Records are "product" types
- (Functions are "exponent" types)
That's all you need!
[] -- empty list
[1, 2, 6] : List number
["Hello", "world"] : List String
Lists
[] -- empty list
[1, 2, 6] : List number
["Hello", "world"] : List String
["Hello", 42] -- impossible!
Lists are homogeneous
ages : List Int
ages = [ 18, 14, 35, 10, 51 ]
agesInFiveYears : List Int
agesInFiveYears =
-- add five to each element
No for-loops!
addFive : Int -> Int
addFive x = 5 + x
ages : List Int
ages = [ 18, 14, 35, 10, 51 ]
agesInFiveYears : List Int
agesInFiveYears =
List.map addFive ages
No for-loops!
List.map :
(a -> b)
-> List a
-> List b
agesInFiveYears =
List.map addFive ages
Map signature
ages : List Int
ages = [ 18, 14, 35, 10, 51 ]
-- transform into :
-- [ "18 ans", "14 ans", ... ]
-- Hint:
-- String.fromInt : Int -> Str
Map challenge
ages : List Int
ages = [ 18, 14, 35, 10, 51 ]
displayAge : Int -> String
displayAge age =
String.fromInt age ++ " ans"
agesDisplayed =
List.map displayAge ages
Map challenge
{-| Compute the total number of chars in the
list of strings given in argument. Example:
totalLength ["hey!", "I am", "Hungry!!"]
returns 16
-}
totalLength : List String -> Int
totalLength strings = ...
-- HINT: List.sum : List Int -> Int
Map challenge 2
{-| Compute the total number of chars in the
list of strings given in argument. Example:
totalLength ["hey!", "I am", "Hungry!!"]
returns 16
-}
totalLength : List String -> Int
totalLength strings =
List.sum (List.map String.length strings)
Map challenge 2
Implement a Nim game
https://ellie-app.com/fF4PS3bjTb7a1
Rules:
- 10 lucifers at the beginning
- 2 players
- at his turn, the player can take 1,2 or 3 matches
- the player taking the last lucifer lost
Talks
By groups of ~2, about 5-10 mins.
- Trees (the data structure): examples, how to implement it in elm, some basic algorithms (e.g. computing depth) -> Lionel, Teddy, Ilyane
- Modules: how do they work in elm? How do we use them to enforce some properties (give concrete examples)? Keyword: Opaque Type
-> Hugo, Jacky - List.foldr/List.foldl: explain how it works, give some examples (maybe compare some "for loop" implementation with foldX one?). How to write "map" from it?
-> Léo, Luis - Lists: How could we define the List type ourself? How to implement length/map/filter with this implementation? (to simplify, we could just define "List of Ints")
-> Rémy, Nacer - Maybe/Result: how do we handle errors in Elm? Give the definition of those types. Give examples with "map" (and if you feel it, "andThen")
-> Maxime, Gaspard
-- True if the 1st arg is in the second arg
member : a -> List a -> Bool
-- True if any element of the list is True
any : List Bool -> Bool
-- True if all elements of the list is True
all : List Bool -> Bool
-- rewrite member using map and any
isAscending : List Int -> Bool
Exercises on list
implement those functions using recursion and List.foldl (except for the last: use only recursion)
import Dict exposing (Dict)
d1 = Dict.empty
d2 = Dict.insert "Seb" 42 d1
age = case Dict.get "Seb" d2 of
Just a -> "Seb is " ++ String.fromInt a
Nothing -> "I don't know Seb"
d3 =
Dict.fromList [("Seb", 42), ("George", 45)]
Dictionary
associate a key to a value
Dictionary
associate a key to a value
See the docs:
https://package.elm-lang.org/packages/elm/core/latest/Dict
Keys have to be comparable:
String, Int, Float, List and Tuples of comparable are comparable
Challenge:
People list!
https://github.com/sebsheep/intro-to-fp/tree/main/contact-list
Follow the TODOs!
Parsing
Parsing
type alias Affectation =
{ varName : String
, value : Int
}
fromString :
String
-> Affectation
fromString "foo = 3"
--{varName="foo",value=3}
Challenges:
Introduction to Functional Programming
By sebbes
Introduction to Functional Programming
- 437