Upload
stan-lea
View
82
Download
1
Embed Size (px)
Citation preview
Functional ScalaThe Math Connection: From Functions to Free Monads
https://github.com/ReactivePatterns/functional-scala
Functional IngredientsThe Math Connection
• Functions
• Higher Order Functions (chaining with map, reduce, etc.)
• For-Comprehensions
• Monads (chainable computation steps)
• Algebraic Data Types (functional APIs)
• Free Monads (interpreters)
Basic Scala Concepts• 3 fundamental building blocks: expressions, values, types
• Valid expressions have a type and calculate a value
• Literals are the simplest expressions
• Blocks are compound expressions built with operators and flow control expressions (e.g. conditionals)
• Expressions can be pure or can have side-effects
• Every value is an object
• Reusability support: value declarations, functions, methods
• Programs are built from the building blocks (abstractions and reusability are not required and often avoided)
Basic Functional IngredientsScala Math
Functionf: A => B
A and B are types
f: A → B
A and B are sets
HOFList[A] method:
map[B](f: A => B): List[A]
{f(a) | a ∈ A}
Generalizes to objects in categories
SequenceComprehension
for (i <- List.range(0, 20) if i % 2 == 0) yield i
List(0, 2, 4, 6, 8, 10, 12, 14, 16, 18){i | i ∈ ℕ, 0 ≤ i < 20, i ≡ 0 (mod 2)}
ForComprehension
for { i <- 0 until 20; j <- i until 20 if i + j == 32 } yield Pair(i, j);
(13, 19) (14, 18) (15, 17) (16, 16)
{(i, j) | i, j ∈ ℕ, 0 ≤ i, j < 20, i + j = 32}
Sequential Computation1. What comes next?
• 1, 3, 5, 7, ?
• 0, 1, 1, 2, 3, 5, ?
2. Steps can be ordered linearly or as a (directed acyclic) graph
3. Steps can be: expressions, functions, abstractions
4. Each step represents or produces a value
Example: Alexa Volume API
level
Volume
level: Int
Volume[Int]
level: Double
Volume[Double]
f
flatMap(f)
Unit, FlatMap, Map and For-Comprehensions
level: Int
Volume[Int]
level: Double
Volume[Double]
f
map(f)
level
Volume
level
Volume
f
flatMap(unit(f))
unit(f)
unit
Flatten
level: A
Volume[A]
level: A
Volume[A]
f
flatMap(f)
Volume[Volume[A]]
map(f)flatten
Compose
level: A
Volume[A]
level: B
Volume[B]
f
flatMap(f)
level: C
Volume[C]
g
flatMap(g)
MonadsThree elements:
1. Type constructor F[_] that takes one argument (e.g. List, Function0, Option, Either, Future)
2. A monadic unit, a function that takes a value of any type A and produces a value of type F[A]
3. A monadic composition operation that takes a function of type A => F[B], and a function of type B => F[C] and produces a function of type A => F[C]
Two laws:
1. Identity: compose(unit, f) = f = compose(f, unit)
2. Associativity: compose(compose(f, g), h) = compose(f, compose(g, h))
Example: Statistical Distributions
sample
Distribution
Dice Throwing As a Computation
The Monty Hall Problemto switch or
not to switch?
Monty Hall Problem As a Computation
vs
Functional Derivation of Distributions
Existing Monad Implementations
• Cats
• Scalaz
• Akka Agents
• Observable
• Unfortunately NOT Akka Streams
API Functional Design• Behavior + Types = Algebra
• Return abstractions (monadic types like Try, Either, Future, Observable, etc.)
Railway Oriented ProgrammingDesigning For Failure
Implementation• Functions are lifted to monadic steps (could do that automatically, a topic for another talk)
• State can be managed in a functional manner too (a topic for another talk)
For-Comprehensions or Direct FlatMaps Allow Step Sequencing/Composition
Future Based VersionAkka Agents are used to manage state
HTTP Endpoint
Contracts as Union TypesADT = Algebraic Data Type
Free Monads as Interpreters• represent stateful computations as data, and run them
• run recursive computations in a stack-safe way
• build an embedded DSL (domain-specific language)
• retarget a computation to another interpreter using natural transformations
https://github.com/typelevel/cats/blob/master/docs/src/main/tut/freemonad.md
Free APIWrite a sequence of instructions in the embedded DSL as a "program", compile the "program", and finally execute the "program" to interact with the actual key-value store.
Interpreters/CompilersDependency Injection done right
Logic is Passed to InterpretersStructure, interpretation and execution are separate concerns
Advanced Topic: Lifting Functions Two Instructions Are Enough
Summary and Conclusions
• Abstractions give an unfair advantage
• Map and FlatMap are sometimes enough
• Composition through For-Comprehensions is readily available
• Standardizing computation steps pays big
• Functions are enough as building blocks (they can be lifted to objects, actors, etc.)