Video and slides synchronized, mp3 and slide download available at URL http://bit.ly/1gZiqcN.
Runar Bjarnason explains how to approach I/O from a purely functional perspective, exploring the space of existing solutions, their benefits, and drawbacks.Filmed at qconnewyork.com.
Runar Bjarnason is an independent software developer, co-author of "Functional Programming in Scala" (Manning, 2013), and a functional programming extremist.
2. Watch the video with slide
synchronization on InfoQ.com!
http://www.infoq.com/presentations
/io-functional-side-effects
InfoQ.com: News & Community Site
• 750,000 unique visitors/month
• Published in 4 languages (English, Chinese, Japanese and Brazilian
Portuguese)
• Post content from our QCon conferences
• News 15-20 / week
• Articles 3-4 / week
• Presentations (videos) 12-15 / week
• Interviews 2-3 / week
• Books 1 / month
3. Presented at QCon New York
www.qconnewyork.com
Purpose of QCon
- to empower software development by facilitating the spread of
knowledge and innovation
Strategy
- practitioner-driven conference designed for YOU: influencers of
change and innovation in your teams
- speakers and topics driving the evolution and innovation
- connecting and catalyzing the influencers and innovators
Highlights
- attended by more than 12,000 delegates since 2007
- held in 9 cities worldwide
4. Who is this jackass?
•
•
•
Thursday, June 13, 13
Enterprise Java refugee
Author, Functional Programming in Scala
manning.com/bjarnason
Partially responsible for Scalaz and
Functional Java
5. What you should take
away from this talk
•
•
•
Thursday, June 13, 13
I/O can be done with pure functional
programming.
It really is purely functional.
How it’s done and why it’s done that way.
15. An expression e is referentially transparent if for all
programs p every occurrence of e in p can be replaced
with the result of evaluating e without changing the
meaning of p.
Thursday, June 13, 13
16. A function f is pure if f(x) is RT when x is RT.
Thursday, June 13, 13
17. A pure function always returns the same value
given the same input.
Thursday, June 13, 13
18. A pure function does not depend on anything
other than its argument.
Thursday, June 13, 13
19. The result of calling a pure function can be understood
completely by looking at the returned value.
Thursday, June 13, 13
24. def x = new Date().getTime
def y = 4
def p = x + y
Thursday, June 13, 13
25. def y = 4
def p = 1369250684475 + y
Thursday, June 13, 13
26. A side-effect is anything that violates referential
transparency.
Thursday, June 13, 13
27. Problems with sideeffecting I/O
•
•
•
•
•
Thursday, June 13, 13
Any function can perform I/O
Monolithic, non-modular, limited reuse
Novel compositions difficult
Difficult to test
Difficult to scale
28. What we want
•
•
•
•
Thursday, June 13, 13
Clear separation of I/O concern
Modular and compositional API
Easy to test
Scales well
29. class Cafe {
def buyCoffee(cc: CreditCard): Coffee = {
val cup = new Coffee()
Payments.charge(cc, cup.price)
cup
}
}
Thursday, June 13, 13
30. class Cafe {
def buyCoffee(cc: CreditCard, p: Payments): Coffee = {
val cup = new Coffee()
p.charge(cc, cup.price)
cup
}
}
Thursday, June 13, 13
31. class Cafe {
def buyCoffee(cc: CreditCard): (Coffee, Charge) = {
val cup = new Coffee()
(cup, new Charge(cc, cup.price))
}
}
Thursday, June 13, 13
32. First-class I/O
Instead of performing I/O as a side-effect,
return a value to the caller that describes an
interaction with the external system.
Thursday, June 13, 13
43. Haskell
do
putStrLn "What is your name?"
putStrLn ("Hello, " ++ getLine)
Couldn't match expected type `String' with
actual type `IO String'
In the second argument of `(++)', namely
`getLine'
Thursday, June 13, 13
44. Haskell
putStrLn "What is your name?" >>
getLine >>= greet
greet name = putStrLn ("Hello, " ++ name)
Thursday, June 13, 13
46. In Haskell, every program is
a single referentially transparent expression.
Thursday, June 13, 13
47. Benefits of IO
datatype
•
•
•
Thursday, June 13, 13
No side-effects. An IO action is a RT
description.
Effects are external to our program.
Action-manipulating functions!
52. The end of the world
sealed trait RealWorld
abstract class Program {
private val realWorld = new RealWorld {}
final def main(args: Array[String]): Unit =
pureMain(args).apply()
def pureMain(args: IndexedSeq[String]): IO[Unit]
}
Thursday, June 13, 13
53. Example IO actions
def io[A](a: => A): IO[A] =
new IO(() => a)
def putStrLn(s: String): IO[Unit] =
io(println(s))
def getLine: IO[String] =
io(readLine)
Thursday, June 13, 13
63. The “free monad”
model
sealed trait IO[A]
case class Pure[A](a: A) extends IO[A]
case class Request[I,A](
req: External[I],
k: I => IO[A]) extends IO[A]
Thursday, June 13, 13
64. The “free monad”
model
sealed trait IO[F[_],A]
case class Pure[F[_],A](a: A) extends IO[F,A]
case class Request[F[_],I,A](
req: F[I],
k: I => IO[A]) extends IO[A]
Thursday, June 13, 13
65. Any effect
trait Runnable[A] { def run: A }
def delay[A](a: => A) =
new Runnable[A] {
def run = a
}
type AnyIO[A] = IO[Runnable,A]
Thursday, June 13, 13
66. Console I/O
trait Console[A]
case object ReadLine extends Console[Option[String]]
case class PrintLn(s: String) extends Console[Unit]
type ConsoleIO[A] = IO[Console,A]
Thursday, June 13, 13
67. The end of the world
trait Run[F[_]] {
def apply[A](expr: F[A]): (A, Run[F])
}
abstract class App[F[_]](R: Run[F]) {
def main(a: Array[String]): IO[F,Unit] =
run(pureMain(a))
def pureMain(a: Array[String]): IO[F,Unit]
}
Thursday, June 13, 13
def run[A](io: IO[F,A]): A =
io match {
case Pure(a) => a
case Request(req, k) =>
val (e, r2) = R(expr)
run(r2)(k(e))
}
68. Console I/O
object RunConsole extends Run[Console] {
def apply[A](c: Console[A]) = c match {
case ReadLine => (Option(readLine), RunConsole)
case PrintLn(s) => (println(s), RunConsole)
}
}
IO.run(RunConsole): IO[Console,A] => A
Thursday, June 13, 13
69. We can use this same model for
•
•
•
•
•
•
Thursday, June 13, 13
file system access
network sockets
HTTP requests
JDBC actions
system clock access
non-blocking I/O
70. Summary
•
•
•
It really is purely functional.
•
Thursday, June 13, 13
I/O can be done with pure functional
programming.
Now you know how it’s done.
You don’t need a purely functional
language to do it.
71. Afterword
•
•
•
•
Thursday, June 13, 13
There’s a lot more to be said
This presentation is simplified
Streaming I/O
Mutable arrays and references