EFFECTING PURE CHANGE
HOW ANYTHING EVER GETS DONE IN FP
ANUPAM JAIN
2
Hello!
3
❑ MEETUP: https://www.meetup.com/DelhiNCR-Haskell-And-
Functional-Programming-Languages-Group
❑ TELEGRAM: https://t.me/fpncr
❑ GITHUB: https://github.com/fpncr
❑ SLACK: https://functionalprogramming.slack.com #FPNCR
FPNCR
4
Effects
5
❑ Programming with Mathematical Functions.
❑ A Function has Input and Output.
❑ Referentially Transparent
❑ A complete Program is just a function!
Functional Programming
6
❑ No Global State
❑ No Assignments
❑ No Statements
❑ No Input-Output
Referential Transparency
7
❑ Easier to Reason About
❑ Easier to Optimize
❑ Easier to Parallelize
❑ Easier to Test
❑ ???
Why?
8
SideEffects!!
9
What Happens If we
Ignore the Danger
10
write :: String -> ()
read :: () -> String
What could go wrong
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
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
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
OCAML
let val ha = (print "ha") in ha; ha end
HASKELL
let ha = putStr “ha” in ha >> ha
Referential Transparency is Vital
ha
haha
15
Taming Side Effects
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.
17
Effectful Logic
Pure Logic
Outside World
18
❑ React – Functional Views
❑ The Elm Architecture
❑ Functional Reactive Programming
❑ Monads and Algebraic Effects
Examples
19
render() {
let n = this.state.count
return <button onClick = {setState({count:n+1})}>{n}</button>
}
React – Functional Views
20
view address model =
button [onClick address Increment] [text (toString model)]
update action model = case action of
Increment -> model + 1
The Elm Architecture
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
❑ 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
❑ 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
❑ text :: Behaviour String -> IO ()
❑ button :: Event ()
❑ gui = do
clicks <- button
text hold “Not Clicked” (map (_ -> “Clicked!”) clicks)
FRP GUIs
25
Monads
26
❑ Tagged values
❑ Provide explicit control over sequencing
Monads
IO String
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
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
29
x <- foo
…
Sprinkle Some Syntactic Sugar
foo (x -> …)
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
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
❑ Callbacks are generally associated with Asynchronous code
❑ Do notation avoids “Callback Hell”
Asynchronous
Computations are Effects
ajax GET “google.com" (response -> …)
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 ->
…
) ) )
34
if(ans == "Yes") orderPizza
else ???
Where is the Else block?
35
if(ans == "Yes") orderPizza
else return ()
Where is the Else block?
36
Type: IO a
Bind: IO a -> (a -> IO b) -> IO b
Return: a -> IO a
The Monad
37
❑ Reader
❑ Logger
❑ State
❑ Exceptions
❑ Random
❑ …
Bring Your Own Monad
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
main = runReader myConfig do
res <- foo
bar res
foo = do config <- ask; …
bar res = do config <- ask; …
Reader Monad
40
“Haskell” is the world’s finest
imperative programming
language.
~Simon Peyton Jones
41
“Haskell” is the world’s finest
imperative programming
language.
~Simon Peyton Jones
(Creator of Haskell)
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
43
data Console callback
= Read (String -> callback)
| Write String callback
handle (Read cb) = …
handle (Write s cb) = …
Console Effect PSEUDO-CODE
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
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
handle (Return x) = return (x,””);
handle (Write s cb) = (x,rest) = do cb(); return (x, s:rest);
Returning Values from
Handlers PSEUDO-CODE
47
SideEffects!!
48
BestFriends!!
49
Thank You

Effecting Pure Change - How anything ever gets done in functional programming languages - Anupam Jain (S&P Global)

  • 1.
    EFFECTING PURE CHANGE HOWANYTHING EVER GETS DONE IN FP ANUPAM JAIN
  • 2.
  • 3.
    3 ❑ MEETUP: https://www.meetup.com/DelhiNCR-Haskell-And- Functional-Programming-Languages-Group ❑TELEGRAM: https://t.me/fpncr ❑ GITHUB: https://github.com/fpncr ❑ SLACK: https://functionalprogramming.slack.com #FPNCR FPNCR
  • 4.
  • 5.
    5 ❑ Programming withMathematical Functions. ❑ A Function has Input and Output. ❑ Referentially Transparent ❑ A complete Program is just a function! Functional Programming
  • 6.
    6 ❑ No GlobalState ❑ No Assignments ❑ No Statements ❑ No Input-Output Referential Transparency
  • 7.
    7 ❑ Easier toReason About ❑ Easier to Optimize ❑ Easier to Parallelize ❑ Easier to Test ❑ ??? Why?
  • 8.
  • 9.
    9 What Happens Ifwe Ignore the Danger
  • 10.
    10 write :: String-> () read :: () -> String What could go wrong
  • 11.
    11 write "Do youwant 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 youwant 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 youwant 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
  • 15.
  • 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.
  • 17.
  • 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 betweenthings 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
  • 25.
  • 26.
    26 ❑ Tagged values ❑Provide explicit control over sequencing Monads IO String
  • 27.
    27 ❑ Values canbe 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 youwant a pizza?" ( () -> read ( ans -> if (ans == "Yes") orderPizza ( () -> write "Should I launch missiles?" ( () -> read ( ans -> if (ans == "Yes") launchNukes () ) ) ) ) ) Continuation Passing Style
  • 29.
    29 x <- foo … SprinkleSome Syntactic Sugar foo (x -> …)
  • 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 "Doyou 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 aregenerally associated with Asynchronous code ❑ Do notation avoids “Callback Hell” Asynchronous Computations are Effects ajax GET “google.com" (response -> …)
  • 33.
    33 do post <- ajaxGET “/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 -> … ) ) )
  • 34.
    34 if(ans == "Yes")orderPizza else ??? Where is the Else block?
  • 35.
    35 if(ans == "Yes")orderPizza else return () Where is the Else block?
  • 36.
    36 Type: IO a Bind:IO a -> (a -> IO b) -> IO b Return: a -> IO a The Monad
  • 37.
    37 ❑ Reader ❑ Logger ❑State ❑ Exceptions ❑ Random ❑ … Bring Your Own Monad
  • 38.
    38 Type: Reader ea :: 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 = runReadermyConfig do res <- foo bar res foo = do config <- ask; … bar res = do config <- ask; … Reader Monad
  • 40.
    40 “Haskell” is theworld’s finest imperative programming language. ~Simon Peyton Jones
  • 41.
    41 “Haskell” is theworld’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
  • 43.
    43 data Console callback =Read (String -> callback) | Write String callback handle (Read cb) = … handle (Write s cb) = … Console Effect PSEUDO-CODE
  • 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 scb) = 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
  • 47.
  • 48.
  • 49.