Newcomers to functional programming are often mystified when they encounter pure functions and immutable data structures. A mathematical function which always produces the same output for the same input is so inflexible as to be almost useless! And surely how can you even represent even the simplest of dynamic program state without variables to store it in, to say nothing of fancy user interfaces, and complex input output.
This talk will present an overview of the various techniques that are used by functional programming languages to tackle state and external "effects" which are needed for any real world program. It will cover a large landscape ranging from Monads, to Algebraic Effects, to Functional Reactive Programming. And it will show how functional programming can be as *useful* for real world programs, as it is *beautiful*.
5. 5
❑ Programming with Mathematical Functions.
❑ A Function has Input and Output.
❑ Referentially Transparent
❑ A complete Program is just a function!
Functional Programming
6. 6
❑ No Global State
❑ No Assignments
❑ No Statements
❑ No Input-Output
Referential Transparency
7. 7
❑ Easier to Reason About
❑ Easier to Optimize
❑ Easier to Parallelize
❑ Easier to Test
❑ ???
Why?
11. 11
write "Do you want a pizza?"
if (read() == "Yes") orderPizza()
write "Should I launch missiles?"
if (read() == "Yes") launchMissiles()
What could go wrong
PSEUDO-CODE
12. 12
write "Do you want a pizza?"
if (read() == "Yes") orderPizza()
write "Should I launch missiles?"
if (read() == "Yes") launchMissiles()
What could go wrong
May be optimized away
13. 13
write "Do you want a pizza?"
if (read() == "Yes") orderPizza()
write "Should I launch missiles?"
if (read() == "Yes") launchMissiles()
What could go wrong
May reuse value from
previous read()
14. 14
OCAML
let val ha = (print "ha") in ha; ha end
HASKELL
let ha = putStr “ha” in ha >> ha
Referential Transparency is Vital
ha
haha
16. 16
❑ Separate “Effects” from “Values”
(Hint: Strong Types are great for this)
❑ Effects are forever. No way to recover a “pure” Value.
❑ As much as possible, tag the flavor of side effects. “Print”
cannot launch nukes.
Contain. Not Prohibit.
18. 18
❑ React – Functional Views
❑ The Elm Architecture
❑ Functional Reactive Programming
❑ Monads and Algebraic Effects
Examples
19. 19
render() {
let n = this.state.count
return <button onClick = {setState({count:n+1})}>{n}</button>
}
React – Functional Views
20. 20
view address model =
button [onClick address Increment] [text (toString model)]
update action model = case action of
Increment -> model + 1
The Elm Architecture
21. 21
❑ Interface between things that are static and those that vary
❑ Forms a graph of relationships between varying things
❑ The program creates the graph, and then lets things run. Akin
to cellular automata.
Functional Reactive
Programming
22. 22
❑ Event a – e.g. Button Clicks
❑ Behaviour a – e.g. System Time
❑ toBehaviour :: Event a -> Behaviour a
❑ mergeEvents :: Event a -> Event a -> Event a
❑ zipBehaviour :: (a -> b -> c) -> Behaviour a -> Behaviour b ->
Behaviour c
FRP Primitives
23. 23
❑ Event a – e.g. Button Clicks
❑ Behaviour a – e.g. System Time
❑ hold :: Event a -> Behaviour a
❑ sample :: Behaviour a -> Event b -> Event (a,b)
❑ merge :: Event a -> Event a -> Event a
❑ zip :: Behaviour a -> Behaviour b -> Behaviour (a,b)
FRP Primitives
24. 24
❑ text :: Behaviour String -> IO ()
❑ button :: Event ()
❑ gui = do
clicks <- button
text hold “Not Clicked” (map (_ -> “Clicked!”) clicks)
FRP GUIs
27. 27
❑ Values can be evaluated in any order (or left unevaluated).
❑ Effects need explicit control over sequencing and sharing.
❑ The only way sequencing is possible in FP is through nested
functions. i.e. Callbacks.
Controlling Sequencing
write "Hello" (() -> write "World")
28. 28
write "Do you want a pizza?" (
() -> read (
ans -> if (ans == "Yes") orderPizza (
() -> write "Should I launch missiles?" (
() -> read (
ans -> if (ans == "Yes") launchNukes () ) ) ) ) )
Continuation Passing Style
30. 30
() <- write "Do you want a pizza?“
ans <- read
if(ans == "Yes") () <- orderPizza
() <- write "Should I launch missiles?“
ans <- read
if (ans == "Yes") () <- launchNukes
Sprinkle Some Syntactic Sugar
write "Do you want a pizza?" (() ->
read (ans ->
if (ans == "Yes") orderPizza (() ->
write "Should I launch missiles?" (() ->
read (ans ->
if (ans == "Yes") launchNukes () ) ) ) ) )
31. 31
do write "Do you want a pizza?“
ans <- read
if(ans == "Yes") orderPizza
write "Should I launch missiles?“
ans <- read
if (ans == "Yes") launchNukes
Do notation
32. 32
❑ Callbacks are generally associated with Asynchronous code
❑ Do notation avoids “Callback Hell”
Asynchronous
Computations are Effects
ajax GET “google.com" (response -> …)
33. 33
do
post <- ajax GET “/post/1“
map post.comments (cid -> do
comment <- ajax GET “/comments/{cid}“
…
)
Avoiding Callback Hell
ajax GET “/post/1" (post ->
map post.comments (cid ->
ajax GET “/comments/{cid}" (comment ->
…
) ) )
38. 38
Type: Reader e a :: e -> a
Bind: Reader e a -> (a -> Reader e b) -> Reader e b
Return: a -> Reader e a
ask: Reader e e
runReader: e -> Reader e a -> a
Reader Monad
39. 39
main = runReader myConfig do
res <- foo
bar res
foo = do config <- ask; …
bar res = do config <- ask; …
Reader Monad
40. 40
“Haskell” is the world’s finest
imperative programming
language.
~Simon Peyton Jones
41. 41
“Haskell” is the world’s finest
imperative programming
language.
~Simon Peyton Jones
(Creator of Haskell)
42. 42
❑ Like Monads, you can define your own Effects
❑ But you can define the usage and handling of the effects
separately
❑ And effects compose freely (pun intended)
Algebraic Effects
44. 44
data Console callback
= Read (String -> callback)
| Write String callback
handle (Read cb) = s = do readLine(); cb(s)
handle (Write s cb) = do console.log(s); cb()
Console Effect PSEUDO-CODE
45. 45
handle (Write s cb) = do console.log(s); console.log(s); cb();
handle (Write s cb) = cb();
handle (Write s cb) = do cb(); console.log(s);
handle (Write s cb) = do if(test(s)) console.log(s); cb();
You can do more things
PSEUDO-CODE
46. 46
handle (Return x) = return (x,””);
handle (Write s cb) = (x,rest) = do cb(); return (x, s:rest);
Returning Values from
Handlers PSEUDO-CODE