"Advanced"
Functional Programming
For the absolute beginner
(a → F[b]) → F[a] → F[b]
(a -> b) → F[a] → F[b]
λx.x
Algebraic Data Types
> let a = (false, false);;
val a : bool * bool = (false, false)
> let b = (false, true);;
val b : bool * bool = (false, true)
> let c = (true, false);;
val c : bool * bool = (true, false)
> let d = (true, true);;
val d : bool * bool = (true, true)
Product Types
type Result =
| Success of int
| Failure of string
let half x =
if x % 2 = 0 then Success (x/2)
else Failure "That's not an even number"
Sum Types
> half 8;;
val it : Result = Success 4
> half 7;;
val it : Result = Failure "That's not an even number"
val half : x:int -> Result
Object Inheritance Hierarchy
Lambda Calculus
λ
Lambda Calculus
The world's smallest universal programming language
<expression := <name> | <function> | <application>
<function> := λ<name>.<expression>
<application> := <expression><expression>
Lambda Calculus
Functions
λx.x
(λx.x)y
≡ y
Lambda Calculus
Application
(λxy.x)E1E2
≡ E1
(λxy.x)E1
≡ λy.E1
(λxy.y)E1E2
≡ E2
(λxy.y)E1
≡ λy.y
Lambda Calculus
Application
a b c d
≡
((a b) c) d
> printf "%s" "Hello\n";;
Hello
val it : unit = ()
> printf "%s";;
val it : (string -> unit) = <fun:it@19-7>
> printf "%d";;
val it : (int -> unit) = <fun:it@20-8>
2 + 3 + 5 = 10
(2 + 3) + 5 = 10
2 + (3 + 5) = 10
2 + (3 + 5)
("Hello," + " ") + "World!"
([1; 2] @ [2; 3; 4]) @ [3; 4; 5]
(2 + 3) + 5
"Hello," + (" " + "World!")
[1; 2] @ ([2; 3; 4] @ [3; 4; 5])
SEMIGROUP
So What?
2 + 3 = 5
2 + 0 = 2
n + 0 = n
Identity
2 * 3 = 6
2 * 1 = 2
n * 1 = n
Identity
MONOID
So What?
[1; 2; 3; 4; 5]
[2; 3; 4; 5; 6]
x → x + 1
List [Int]
List [Int]
Int → Int
List [Int]
List [String]
Int → String
F#
> List.map (fun x -> x + 1) [1; 2; 3];;
val it : int list = [2; 3; 4]
>>> [x + 1 for x in [1, 2, 3]]
[2, 3, 4]
Python
(map (fn [x] (+ x 1)) [1 2 3])
=> (2 3 4)
Clojure
λ map (+1) [1, 2, 3]
[2,3,4]
Haskell
λ [i+1 | i <- [1, 2, 3]]
[2,3,4]
>>> map (lambda x: x+1, [1, 2, 3])
[2, 3, 4]
for {x <- List(1, 2, 3)} yield x+1
List(2, 3, 4)
Scala
(fun a → b) → List[a] → List[b]
let currencyCodes = ["EUR"; "GBP"; "USD"; "CAD"; "JPY"]
let id x = x
let toLower (s: string) =
s.ToLower()
let addPrefix s =
"x." + s
List.map id currencyCodes
val it : string list = ["EUR"; "GBP"; "USD"; "CAD"; "JPY"]
List.map toLower currencyCodes
val it : string list = ["eur"; "gbp"; "usd"; "cad"; "jpy"]
List.map addPrefix currencyCodes
val it : string list = ["x.EUR"; "x.GBP"; "x.USD"; "x.CAD"; "x.JPY"]
(fun a → b) → List[a] → List[b]
currencyCodes
|> List.map toLower
|> List.map addPrefix
val it : string list = ["x.eur"; "x.gbp"; "x.usd"; "x.cad"; "x.jpy"]
> let listToLower = List.map toLower
val listToLower : (string list -> string list)
> let convertCode = toLower >> addPrefix
val convertCode : (string -> string)
> List.map convertCode currencyCodes
val it : string list = ["x.eur"; "x.gbp"; "x.usd"; "x.cad"; "x.jpy"]
> let convertCodes = listToLower >> listAddPrefix;;
val convertCodes : (string list -> string list)
> convertCodes currencyCodes;;
val it : string list = ["x.eur"; "x.gbp"; "x.usd"; "x.cad"; "x.jpy"]
> listToLower currencyCodes;;
val it : string list = ["eur"; "gbp"; "usd"; "cad"; "jpy"]
It's not just Lists
let codesByCountry = Map.ofList [
("Ireland", "EUR")
("England", "GBP")
("Scotland", "GBP")
("United States", "USD")
("Canada", "CAD")
("Japan", "JPY")
("Switzerland", "CHF")
]
codesByCountry.["Ireland"];;
val it : string = "EUR"
(fun a → b) → Option[a] → Option[b]
let findInMap map key =
Map.tryFind key map
> let findCode = findInMap codesByCountry
val findCode : (string -> string option)
> findCode "Ireland"
val it : string option = Some "EUR"
> findCode "Australia"
val it : string option = None
> let irlCode = findCode "Ireland";;
val irlCode : string option = Some "EUR"
(fun a → b) → Option[a] → Option[b]
> let ausCode = findCode "Australia";;
val ausCode : string option = None
> Option.map convertCode ausCode;;
val it : string option = None
> Option.map toLower irlCode;;
val it : string option = Some "eur"
> Option.map addPrefix irlCode;;
val it : string option = Some "x.EUR"
> Option.map convertCode irlCode;;
val it : string option = Some "x.eur"
(fun a → b) → Option[a] → Option[b]
(fun a → b) → List[a] → List[b]
(fun a → b) → F[a] → F[b]
List.map
Option.map
fmap (aka map)
Functor
So What?
findCode: string → Option[string]
findCode: string → string
Composition
findRate: string → decimal
findRate: string → Option[decimal]
findCode >> findRate
✔︎
findCode >> findRate
✘
Composition
let codesByCountry = Map.ofList [
("Ireland", "EUR")
("England", "GBP")
("Scotland", "GBP")
("United States", "USD")
("Canada", "CAD")
("Japan", "JPY")
("Switzerland", "CHF")
]
let rates = Map.ofList [
("x.eur", 1M)
("x.gbp", 0.78883M)
("x.jpy", 123.94M)
("x.usd", 1.13804M)
("x.cad", 1.47397M)
]
let findCode = findInMap codesByCountry
val findCode : (string -> string option)
let findRate = findInMap rates
val findRate : (string -> decimal option)
> Option.bind
val it : (('a -> 'b option) -> 'a option -> 'b option)
(fun a → Option[b]) → Option[a] → Option[b]
"United States" // String
|> findCode // Option[String]
|> Option.map convertCode // Option[String]
|> Option.bind findRate // Option[Decimal]
val it : decimal option = Some 1.13804M
"Australia"
|> findCode
|> Option.map convertCode
|> Option.bind findRate
val it : decimal option = None
"Switzerland"
|> findCode
|> Option.map convertCode
|> Option.bind findRate
val it : decimal option = None
(fun a → Option[b]) → Option[a] → Option[b]
(fun a → List[b]) → List[a] → List[b]
(fun a → F[b]) → F[a] → F[b]
List.collect
Option.bind
bind (aka flatmap)
a → F[a]
return (just wrap a value)
Monad
That's It?
Polymorphism
Inheritance
Easy to add new types, hard to add new behaviour
Parametric
Easy to add new behaviour, hard to add new types
Polymorphism
Typeclasses
Add behaviour to things who's code you don't have access to
Almost like duck typing, but behaviour only for those types for which a typeclass "instance" is available
Still type-safe, compiler checked
Advanced Functional Programming for the absolute beginner
By richardadalton
Advanced Functional Programming for the absolute beginner
- 3,267