SlideShare a Scribd company logo
1 of 195
Download to read offline
Functional Design Patterns
(NDC London 2014)
@ScottWlaschin
fsharpforfunandprofit.com
Functional Design Patterns
@ScottWlaschin
fsharpforfunandprofit.com
X
Functional Design Patterns
@ScottWlaschin
fsharpforfunandprofit.com
HOW I GOT HERE
Me
I
Making fun of Enterprise OO
is like shooting fish in a barrel
I but...
I but...
Making fun of Enterprise OO
is like shooting IMarineVertebrates
in an AbstractBarrelProxyFactory
Inspired by @sjkilleen
I
This is what happens when you dabble too
much in functional programming
https://www.flickr.com/photos/37511372@N08/5488671752/
Haskell programmers
F#/OCaml programmers
Visual Basic programmers
Lisp
programmers
FP DESIGN PATTERNS
• Single Responsibility Principle
• Open/Closed principle
• Dependency Inversion
Principle
• Interface Segregation
Principle
• Factory pattern
• Strategy pattern
• Decorator pattern
• Visitor pattern
OO pattern/principle
• Single Responsibility Principle
• Open/Closed principle
• Dependency Inversion
Principle
• Interface Segregation
Principle
• Factory pattern
• Strategy pattern
• Decorator pattern
• Visitor pattern
OO pattern/principle Borg response
• Single Responsibility Principle
• Open/Closed principle
• Dependency Inversion
Principle
• Interface Segregation
Principle
• Factory pattern
• Strategy pattern
• Decorator pattern
• Visitor pattern
• Functions
• Functions
• Functions, also
• Functions
• You will be assimilated!
• Functions again
• Functions
• Resistance is futile!
OO pattern/principle FP equivalent
Seriously, FP patterns are different
Functional patterns
• Apomorphisms
• Dynamorphisms
• Chronomorphisms
• Zygohistomorphic prepromorphisms
Functional patterns
• Core Principles of FP design
– Functions, types, composition
• Functions as parameters
– Functions as interfaces
– Partial application & dependency injection
– Continuations, chaining & the pyramid of doom
• Monads
– Error handling, Async
• Maps
– Dealing with wrapped data
– Functors
• Monoids
– Aggregating data and operations
This talk
A whirlwind tour of many sights
Don't worry if you don't understand everything
(SOME) CORE PRINCIPLES OF
FUNCTIONAL PROGRAMMING
Important to understand!
Core principles of FP
Function
Types are not classes
Functions are things
Composition everywhere
Core principle:
Functions are things
Function
Functions as things
The Tunnel of
Transformation
Function
apple -> banana
A function is a standalone thing,
not attached to a class
Functions as things
let z = 1
int-> int->int
1
let add x y = x + y
Functions as inputs and outputs
let useFn f = (f 1) + 2
let add x = (fun y -> x + y)
int->(int->int)
int
int
let transformInt f x = (f x) + 1
int int
int->int
Function as output
Int ->int
Function as input
Function as parameterint->int
(int->int)->int
int->int
Core principle:
Composition everywhere
Function composition
Function 1
apple -> banana
Function 2
banana -> cherry
Function composition
>>
Function 1
apple -> banana
Function 2
banana -> cherry
Function composition
New Function
apple -> cherry
Can't tell it was built from
smaller functions!
Design paradigm:
Functions all the way down
“Functions in the small,
objects in the large”
Low-level operation
ToUpper
stringstring
Low-level operation
Service
AddressValidator
A “Service” is just like a microservice
but without the "micro" in front
Validation
Result
Address
Low-level operation Low-level operation
Service
Use-case
UpdateProfileData
ChangeProfile
Result
ChangeProfile
Request
Service Service
Use-case
Web application
Http
Response
Http
Request
Use-case Use-case
Core principle:
Types are not classes
X
Types are not classes
Set of
valid inputs
Set of
valid outputs
So what is a type?
Types separate data from behavior
Lists Lists
List.map
List.collect
List.filter
List.etc
Types can be composed too
“algebraic types"
Product types
× = Alice, Jan 12th
Bob, Feb 2nd
Carol, Mar 3rd
Set of people Set of dates
type Birthday = Person * Date
Sum types
Set of Cash values
Set of Cheque values
Set of CreditCard
values
+
+
type PaymentMethod =
| Cash
| Cheque of ChequeNumber
| Card of CardType * CardNumber
Design principle:
Strive for totality
twelveDividedBy(x)
input x maps to 12/x
…
3
2
1
0
…
Domain (int) Codomain (int)
…
4
6
12
…
Totality
int TwelveDividedBy(int input)
{
switch (input)
{
case 3: return 4;
case 2: return 6;
case 1: return 12;
case 0: return ??;
}
}
twelveDividedBy(x)
input x maps to 12/x
…
3
2
1
0
…
Domain (int) Codomain (int)
…
4
6
12
…
Totality
int TwelveDividedBy(int input)
{
switch (input)
{
case 3: return 4;
case 2: return 6;
case 1: return 12;
case 0: return ??;
}
} What happens here?
twelveDividedBy(x)
input x maps to 12/x
…
3
2
1
0
…
Domain (int) Codomain (int)
…
4
6
12
…
Totality
int TwelveDividedBy(int input)
{
switch (input)
{
case 3: return 4;
case 2: return 6;
case 1: return 12;
case 0:
throw InvalidArgException;
}
}
int -> int
This type signature is a lie!
You tell me you can
handle 0, and then you
complain about it?
twelveDividedBy(x)
input x maps to 12/x
…
3
2
1
-1
…
NonZeroInteger int
…
4
6
12
…
Totality
int TwelveDividedBy(int input)
{
switch (input)
{
case 3: return 4;
case 2: return 6;
case 1: return 12;
case -1: return -12;
}
}
Constrain the input
0 doesn’t have to
be handled
NonZeroInteger -> int
0 is missing
Types are documentation
twelveDividedBy(x)
input x maps to 12/x
…
3
2
1
0
-1
…
int Option<Int>
…
Some 4
Some 6
Some 12
None
…
Totality
int TwelveDividedBy(int input)
{
switch (input)
{
case 3: return Some 4;
case 2: return Some 6;
case 1: return Some 12;
case 0: return None;
}
}
Extend the output
0 is valid input
int -> int option
Types are documentation
Design principle:
Use static types for domain
modelling and documentation
Static types only!
Sorry Clojure and JS
developers 
Big topic! Not enough time today !
More on DDD and designing with types at
fsharpforfunandprofit.com/ddd
FUNCTIONS AS
PARAMETERS
Guideline:
Parameterize all the things
Parameterize all the things
let printList() =
for i in [1..10] do
printfn "the number is %i" i
Parameterize all the things
It's second nature to parameterize the data input:
let printList aList =
for i in aList do
printfn "the number is %i" i
Parameterize all the things
let printList anAction aList =
for i in aList do
anAction i
FPers would parameterize the action as well:
We've decoupled the
behavior from the data.
Any list, any action!
Parameterize all the things
public static int Product(int n)
{
int product = 1;
for (int i = 1; i <= n; i++)
{
product *= i;
}
return product;
}
public static int Sum(int n)
{
int sum = 0;
for (int i = 1; i <= n; i++)
{
sum += i;
}
return sum;
}
public static int Product(int n)
{
int product = 1;
for (int i = 1; i <= n; i++)
{
product *= i;
}
return product;
}
public static int Sum(int n)
{
int sum = 0;
for (int i = 1; i <= n; i++)
{
sum += i;
}
return sum;
}
Parameterize all the things
Parameterize all the things
let product n =
let initialValue = 1
let action productSoFar x = productSoFar * x
[1..n] |> List.fold action initialValue
let sum n =
let initialValue = 0
let action sumSoFar x = sumSoFar+x
[1..n] |> List.fold action initialValue
Lots of collection functions like this:
"fold", "map", "reduce", "collect", etc.
Tip:
Function types are "interfaces"
Function types are interfaces
interface IBunchOfStuff
{
int DoSomething(int x);
string DoSomethingElse(int x);
void DoAThirdThing(string x);
}
Let's take the
Single Responsibility Principle and the
Interface Segregation Principle
to the extreme...
Every interface should have
only one method!
Function types are interfaces
interface IBunchOfStuff
{
int DoSomething(int x);
}
An interface with one method is a just a function type
type IBunchOfStuff: int -> int
Any function with that type is compatible with it
let add2 x = x + 2 // int -> int
let times3 x = x * 3 // int -> int
Strategy pattern
class MyClass
{
public MyClass(IBunchOfStuff strategy) {..}
int DoSomethingWithStuff(int x)
{
return _strategy.DoSomething(x)
}
}
Object-oriented strategy pattern:
Strategy pattern
int int
int->int
int->int
let DoSomethingWithStuff strategy x =
strategy x
Functional strategy pattern:
IBunchOfStuff as parameter
Decorator pattern using function parameter:
let isEven x = (x % 2 = 0) // int -> bool
isEvenint bool
loggerint bool
let logger f input =
let output = f input
// then log input and output
// return output
Decorator pattern using function parameter:
let isEven x = (x % 2 = 0) // int -> bool
isEvenint bool
loggerint bool
let isEvenWithLogging = logger isEven
// int -> bool
Substitutable for original isEven
Decorator pattern using function composition:
let isEven x = (x % 2 = 0) // int -> bool
isEvenint bool
isEvenint boollogint int logbool bool
let isEvenWithLogging = log >> isEven >> log
// int -> bool
Substitutable for original isEven
Composition!
Bad news:
Composition patterns
only work for functions that
have one parameter! 
Good news!
Every function is a
one parameter function 
Writing functions in different ways
let add x y = x + y
let add = (fun x y -> x + y)
let add x = (fun y -> x + y)
int-> int->int
int-> int->int
int-> (int->int)
Normal (Two parameters)
let three = 1 + 2
let three = (+) 1 2
let three = ((+) 1) 2
"+" is a two parameter function
let three = 1 + 2
let three = (+) 1 2
let three = ((+) 1) 2
let add1 = (+) 1
let three = add1 2
No, "+" is a one param function!
Pattern:
Partial application
let name = "Scott"
printfn "Hello, my name is %s" name
let name = "Scott"
(printfn "Hello, my name is %s") name
let name = "Scott"
let hello = (printfn "Hello, my name is %s")
hello name
Can reuse "hello" in many places now!
Pattern:
Use partial application when
working with lists
let names = ["Alice"; "Bob"; "Scott"]
names |> List.iter hello
let hello = printfn "Hello, my name is %s"
let add1 = (+) 1
let equals2 = (=) 2
[1..100]
|> List.map add1
|> List.filter equals2
Pattern:
Use partial application to do
dependency injection
type GetCustomer = CustomerId -> Customer
let getCustomerFromDatabase connection
(customerId:CustomerId) =
// from connection
// select customer
// where customerId = customerId
type of getCustomerFromDatabase =
DbConnection -> CustomerId -> Customer
let getCustomer1 = getCustomerFromDatabase myConnection
// getCustomer1 : CustomerId -> Customer
Persistence ignorant
This function requires a
connection 
The partially applied function does
NOT require a connection – it's baked in! 
type GetCustomer = CustomerId -> Customer
let getCustomerFromMemory dict (customerId:CustomerId) =
dict.Get(customerId)
type of getCustomerFromMemory =
Dictionary<Id,Customer> -> CustomerId -> Customer
let getCustomer2 = getCustomerFromMemory dict
// getCustomer2 : CustomerId -> Customer
This function requires a
dictionary 
The partially applied function does
NOT require a dictionary – it's baked in! 
Pattern:
The Hollywood principle*:
continuations
Continuations
int Divide(int top, int bottom)
{
if (bottom == 0)
{
throw new InvalidOperationException("div by 0");
}
else
{
return top/bottom;
}
}
Method has decided to throw
an exception
(who put it in charge?)
Continuations
void Divide(int top, int bottom,
Action ifZero, Action<int> ifSuccess)
{
if (bottom == 0)
{
ifZero();
}
else
{
ifSuccess( top/bottom );
}
}
Let the caller decide what
happens
what happens next?
Continuations
let divide ifZero ifSuccess top bottom =
if (bottom=0)
then ifZero()
else ifSuccess (top/bottom)
F# version
Four parameters is a lot
though!
Wouldn't it be nice if we could somehow
"bake in" the two behaviour functions....
Continuations
let divide ifZero ifSuccess top bottom =
if (bottom=0)
then ifZero()
else ifSuccess (top/bottom)
let ifZero1 () = printfn "bad"
let ifSuccess1 x = printfn "good %i" x
let divide1 = divide ifZero1 ifSuccess1
//test
let good1 = divide1 6 3
let bad1 = divide1 6 0
setup the functions to:
print a message
Partially apply the
continuations
Use it like a normal function –
only two parameters
let divide ifZero ifSuccess top bottom =
if (bottom=0)
then ifZero()
else ifSuccess (top/bottom)
Continuations
let ifZero2() = None
let ifSuccess2 x = Some x
let divide2 = divide ifZero2 ifSuccess2
//test
let good2 = divide2 6 3
let bad2 = divide2 6 0
setup the functions to:
return an Option
Use it like a normal function –
only two parameters
Partially apply the
continuations
let divide ifZero ifSuccess top bottom =
if (bottom=0)
then ifZero()
else ifSuccess (top/bottom)
Continuations
let ifZero3() = failwith "div by 0"
let ifSuccess3 x = x
let divide3 = divide ifZero3 ifSuccess3
//test
let good3 = divide3 6 3
let bad3 = divide3 6 0
setup the functions to:
throw an exception
Use it like a normal function –
only two parameters
Partially apply the
continuations
Pattern:
Chaining callbacks with
continuations
Pyramid of doom: null testing example
Let example input =
let x = doSomething input
if x <> null then
let y = doSomethingElse x
if y <> null then
let z = doAThirdThing y
if z <> null then
let result = z
result
else
null
else
null
else
null
I know you could do early
returns, but bear with me...
Pyramid of doom: async example
let taskExample input =
let taskX = startTask input
taskX.WhenFinished (fun x ->
let taskY = startAnotherTask x
taskY.WhenFinished (fun y ->
let taskZ = startThirdTask y
taskZ.WhenFinished (fun z ->
z // final result
Pyramid of doom: null example
let example input =
let x = doSomething input
if x <> null then
let y = doSomethingElse x
if y <> null then
let z = doAThirdThing y
if z <> null then
let result = z
result
else
null
else
null
else
null
Nulls are a code smell:
replace with Option!
Pyramid of doom: option example
let example input =
let x = doSomething input
if x.IsSome then
let y = doSomethingElse (x.Value)
if y.IsSome then
let z = doAThirdThing (y.Value)
if z.IsSome then
let result = z.Value
Some result
else
None
else
None
else
None
Much more elegant, yes?
No! This is fugly!
But there is a pattern we can exploit...
Pyramid of doom: option example
let example input =
let x = doSomething input
if x.IsSome then
let y = doSomethingElse (x.Value)
if y.IsSome then
let z = doAThirdThing (y.Value)
if z.IsSome then
// do something with z.Value
// in this block
else
None
else
None
else
None
Pyramid of doom: option example
let example input =
let x = doSomething input
if x.IsSome then
let y = doSomethingElse (x.Value)
if y.IsSome then
// do something with y.Value
// in this block
else
None
else
None
Pyramid of doom: option example
let example input =
let x = doSomething input
if x.IsSome then
// do something with x.Value
// in this block
else
None
Can you see the pattern?
if opt.IsSome then
//do something with opt.Value
else
None
let ifSomeDo f opt =
if opt.IsSome then
f opt.Value
else
None
let example input =
doSomething input
|> ifSomeDo doSomethingElse
|> ifSomeDo doAThirdThing
|> ifSomeDo (fun z -> Some z)
let ifSomeDo f opt =
if opt.IsSome then
f opt.Value
else
None
MONADS
A switch analogy
Some
None
Input ->
Connecting switches
on Some
Bypass on None
Connecting switches
Connecting switches
Composing switches
>> >>
Composing one-track functions is fine...
Composing switches
>> >>
... and composing two-track functions is fine...
Composing switches
 
... but composing switches is not allowed!
How to combine the
mismatched functions?
“Bind” is the answer!
Bind all the things!
Composing switches
Two-track input Two-track input
One-track input Two-track input


Building an adapter block
Two-track input
Slot for switch function
Two-track output
Building an adapter block
Two-track input Two-track output
let bind nextFunction optionInput =
match optionInput with
| Some s -> nextFunction s
| None -> None
Building an adapter block
Two-track input Two-track output
let bind nextFunction optionInput =
match optionInput with
| Some s -> nextFunction s
| None -> None
Building an adapter block
Two-track input Two-track output
let bind nextFunction optionInput =
match optionInput with
| Some s -> nextFunction s
| None -> None
Building an adapter block
Two-track input Two-track output
let bind nextFunction optionInput =
match optionInput with
| Some s -> nextFunction s
| None -> None
Building an adapter block
Two-track input Two-track output
Pattern:
Use bind to chain options
Pyramid of doom: using bind
let bind f opt =
match opt with
| Some v -> f v
| None -> None
let example input =
let x = doSomething input
if x.IsSome then
let y = doSomethingElse (x.Value)
if y.IsSome then
let z = doAThirdThing (y.Value)
if z.IsSome then
let result = z.Value
Some result
else
None
else
None
else
None
let example input =
doSomething input
|> bind doSomethingElse
|> bind doAThirdThing
|> bind (fun z -> Some z)
Pyramid of doom: using bind
Let bind f opt =
match opt with
| Some v -> f v
| None -> None
No pyramids!
Code is linear and clear.
This pattern is called “monadic bind”
Pattern:
Use bind to chain tasks
Connecting tasks
When task
completesWait Wait
Pyramid of doom: using bind for tasks
let taskBind f task =
task.WhenFinished (fun taskResult ->
f taskResult)
let taskExample input =
let taskX = startTask input
taskX.WhenFinished (fun x ->
let taskY = startAnotherTask x
taskY.WhenFinished (fun y ->
let taskZ = startThirdTask y
taskZ.WhenFinished (fun z ->
z // final result
a.k.a “promise” “future”
Pyramid of doom: using bind for tasks
let taskBind f task =
task.WhenFinished (fun taskResult ->
f taskResult)
let taskExample input =
startTask input
|> taskBind startAnotherTask
|> taskBind startThirdTask
|> taskBind (fun z -> z)
This pattern is also a “monadic bind”
Pattern:
Use bind to chain error handlers
Use case without error handling
string UpdateCustomerWithErrorHandling()
{
var request = receiveRequest();
validateRequest(request);
canonicalizeEmail(request);
db.updateDbFromRequest(request);
smtpServer.sendEmail(request.Email)
return "OK";
}
Use case with error handling
string UpdateCustomerWithErrorHandling()
{
var request = receiveRequest();
var isValidated = validateRequest(request);
if (!isValidated) {
return "Request is not valid"
}
canonicalizeEmail(request);
db.updateDbFromRequest(request);
smtpServer.sendEmail(request.Email)
return "OK";
}
Use case with error handling
string UpdateCustomerWithErrorHandling()
{
var request = receiveRequest();
var isValidated = validateRequest(request);
if (!isValidated) {
return "Request is not valid"
}
canonicalizeEmail(request);
var result = db.updateDbFromRequest(request);
if (!result) {
return "Customer record not found"
}
smtpServer.sendEmail(request.Email)
return "OK";
}
Use case with error handling
string UpdateCustomerWithErrorHandling()
{
var request = receiveRequest();
var isValidated = validateRequest(request);
if (!isValidated) {
return "Request is not valid"
}
canonicalizeEmail(request);
try {
var result = db.updateDbFromRequest(request);
if (!result) {
return "Customer record not found"
}
} catch {
return "DB error: Customer record not updated"
}
smtpServer.sendEmail(request.Email)
return "OK";
}
Use case with error handling
string UpdateCustomerWithErrorHandling()
{
var request = receiveRequest();
var isValidated = validateRequest(request);
if (!isValidated) {
return "Request is not valid"
}
canonicalizeEmail(request);
try {
var result = db.updateDbFromRequest(request);
if (!result) {
return "Customer record not found"
}
} catch {
return "DB error: Customer record not updated"
}
if (!smtpServer.sendEmail(request.Email)) {
log.Error "Customer email not sent"
}
return "OK";
}
Use case with error handling
string UpdateCustomerWithErrorHandling()
{
var request = receiveRequest();
var isValidated = validateRequest(request);
if (!isValidated) {
return "Request is not valid"
}
canonicalizeEmail(request);
try {
var result = db.updateDbFromRequest(request);
if (!result) {
return "Customer record not found"
}
} catch {
return "DB error: Customer record not updated"
}
if (!smtpServer.sendEmail(request.Email)) {
log.Error "Customer email not sent"
}
return "OK";
}
A structure for managing errors
Request SuccessValidate
Failure
let validateInput input =
if input.name = "" then
Failure "Name must not be blank"
else if input.email = "" then
Failure "Email must not be blank"
else
Success input // happy path
Connecting switches
Validate UpdateDb SendEmail
Connecting switches
Validate UpdateDb SendEmail
Functional flow without error handling
let updateCustomer =
receiveRequest
|> validateRequest
|> canonicalizeEmail
|> updateDbFromRequest
|> sendEmail
|> returnMessage
Before
One track
let updateCustomerWithErrorHandling =
receiveRequest
|> validateRequest
|> canonicalizeEmail
|> updateDbFromRequest
|> sendEmail
|> returnMessage
Functional flow with error handling
After
See my talk on Friday or
fsharpforfunandprofit.com/rop
Two track
MAPS
World of normal values
int string bool
World of options
int option string option bool option
World of options
World of normal values
int string bool
int option string option bool option

World of options
World of normal values
int option string option bool option

int string bool
let add42ToOption opt =
if opt.IsSome then
let newVal = add42 opt.Value
Some newVal
else
None
How not to code with options
Let’s say you have an int wrapped in an Option, and
you want to add 42 to it:
let add42 x = x + 42

World of options
World of normal values
add42

World of options
World of normal values
add42
Lifting
World of options
World of normal values
T -> U
option<T> -> option<U>
Option.map
World of options
World of normal values
add42
add42ToOptionSome 1 |>
1 |> // 43
// Some 43
The right way to code with options
Let’s say you have an int wrapped in an Option, and
you want to add 42 to it:
let add42 x = x + 42
1 |> add42 // 43
let add42ToOption = Option.map add42
Some 1 |> add42ToOption // Some 43

The right way to code with options
Let’s say you have an int wrapped in an Option, and
you want to add 42 to it:
let add42 x = x + 42
1 |> add42 // 43
Some 1 |> Option.map add42 // Some 43

Lifting to lists
World of lists
World of normal values
T -> U
List<T> -> List<U>
List.map
The right way to code with wrapped types
[1;2;3] |> List.map add42
// [43;44;45]
Lifting to async
World of async
World of normal values
T -> U
async<T> -> async<U>
Async.map
Guideline:
Most wrapped generic types
have a “map”. Use it!
Guideline:
If you create your own generic type,
create a “map” for it.
MONOIDS
Mathematics
Ahead
Thinking like a mathematician
1 + 2 = 3
1 + (2 + 3) = (1 + 2) + 3
1 + 0 = 1
0 + 1 = 1
1 + 2 = 3
Some things
A way of combining
them
2 x 3 = 6
Some things
A way of combining
them
"a" + "b" = "ab"
Some things
A way of combining
them
concat([a],[b]) = [a; b]
Some things
A way of combining
them
1 + 2
1 + 2 + 3
1 + 2 + 3 + 4
Is an integer
Is an integer
A pairwise operation has
become an operation that
works on lists!
1 + (2 + 3) = (1 + 2) + 3
Order of combining doesn’t matter
1 + 2 + 3 + 4
(1 + 2) + (3 + 4)
((1 + 2) + 3) + 4
All the same
1 - (2 - 3) = (1 - 2) - 3
Order of combining does matter
1 + 0 = 1
0 + 1 = 1
A special kind of thing that when
you combine it with something, just
gives you back the original
something
42 * 1 = 42
1 * 42 = 42
A special kind of thing that when
you combine it with something, just
gives you back the original
something
"" + "hello" = "hello"
"hello" + "" = "hello"
“Zero” for strings
The generalization
• You start with a bunch of things, and some way of
combining them two at a time.
• Rule 1 (Closure):The result of combining two things is
always another one of the things.
• Rule 2 (Associativity):When combining more than
two things, which pairwise combination you do first
doesn't matter.
• Rule 3 (Identity element):There is a special thing
called "zero" such that when you combine any thing
with "zero" you get the original thing back. A monoid!
• Rule 1 (Closure):The result of combining two
things is always another one of the things.
• Benefit: converts pairwise operations into
operations that work on lists.
1 + 2 + 3 + 4
[ 1; 2; 3; 4 ] |> List.reduce (+)
1 * 2 * 3 * 4
[ 1; 2; 3; 4 ] |> List.reduce (*)
• Rule 1 (Closure):The result of combining two
things is always another one of the things.
• Benefit: converts pairwise operations into
operations that work on lists.
"a" + "b" + "c" + "d"
[ "a"; "b"; "c"; "d" ] |> List.reduce (+)
• Rule 1 (Closure):The result of combining two
things is always another one of the things.
• Benefit: converts pairwise operations into
operations that work on lists.
• Rule 2 (Associativity):When combining more
than two things, which pairwise combination
you do first doesn't matter.
• Benefit: Divide and conquer, parallelization, and
incremental accumulation.
1 + 2 + 3 + 4
• Rule 2 (Associativity):When combining more
than two things, which pairwise combination
you do first doesn't matter.
• Benefit: Divide and conquer, parallelization, and
incremental accumulation.
(1 + 2) (3 + 4)
3 + 7
• Rule 2 (Associativity):When combining more
than two things, which pairwise combination
you do first doesn't matter.
• Benefit: Divide and conquer, parallelization, and
incremental accumulation.
(1 + 2 + 3)
• Rule 2 (Associativity):When combining more
than two things, which pairwise combination
you do first doesn't matter.
• Benefit: Divide and conquer, parallelization, and
incremental accumulation.
(1 + 2 + 3) + 4
• Rule 2 (Associativity):When combining more
than two things, which pairwise combination
you do first doesn't matter.
• Benefit: Divide and conquer, parallelization, and
incremental accumulation.
(6) + 4
Issues with reduce
• How can I use reduce on an empty list?
• In a divide and conquer algorithm, what should I
do if one of the "divide" steps has nothing in it?
• When using an incremental algorithm, what
value should I start with when I have no data?
• Rule 3 (Identity element):There is a special
thing called "zero" such that when you combine
any thing with "zero" you get the original thing
back.
• Benefit: Initial value for empty or missing data
Pattern:
Simplifying aggregation code with monoids
type OrderLine = {Qty:int; Total:float}
let orderLines = [
{Qty=2; Total=19.98}
{Qty=1; Total= 1.99}
{Qty=3; Total= 3.99} ]
let addPair line1 line2 =
let newQty = line1.Qty + line2.Qty
let newTotal = line1.Total + line2.Total
{Qty=newQty; Total=newTotal}
orderLines |> List.reduce addPair
// {Qty=6; Total= 25.96}
Any combination
of monoids is
also a monoid
Write a pairwise combiner
Profit!
Pattern:
Convert non-monoids to monoids
Customer
+
Customer
+
Customer
Customer Stats
+
Customer Stats
+
Customer Stats
Reduce
Map
Not a monoid A monoid
Customer Stats
(Total)
Hadoop make me a sandwich
https://twitter.com/daviottenheimer
/status/532661754820829185
Guideline:
Convert expensive monoids
to cheap monoids
Log file (Mon)
+
Log File (Tue)
+
Log File (Wed)
=
Really big file
Summary (Mon)
+
Summary (Tue)
+
Summary (Wed)
Map
Strings are monoids A monoid
Much more efficient for
incremental updates
“Monoid homomorphism”
Pattern:
Seeing monoids everywhere
Monoids in the real world
Metrics guideline:
Use counters rather than rates
Alternative metrics guideline:
Make sure your metrics are monoids
• incremental updates
• can handle missing data
Is function composition a monoid?
>>
Function 1
apple -> banana
Function 2
banana -> cherry
New Function
apple -> cherry
Not the same
thing.
Not a monoid 
Is function composition a monoid?
>>
Function 1
apple -> apple
Same thing
Function 2
apple -> apple
Function 3
apple -> apple
A monoid! 
Is function composition a monoid?
“Functions with same type of input and output”
Functions where the input and output are the same type are
monoids! What shall we call these kinds of functions?
Is function composition a monoid?
“Functions with same type of input and output”
“Endomorphisms”
Functions where the input and output are the same type are
monoids! What shall we call these kinds of functions?
All endomorphisms are monoids
let plus1 x = x + 1 // int->int
let times2 x = x * 2 // int->int
let subtract42 x = x – 42 // int->int
Reduce
plus1ThenTimes2ThenSubtract42 // int->int
Endomorphisms
Another endomorphism!
Event sourcing
Any function containing an endomorphism can
be converted into a monoid!
Event application function:
Is an endomorphism
Event -> State -> State
apply event1 // State -> State
apply event2 // State -> State
apply event3 // State -> State
Reduce
applyAllEventsAtOnce // State -> State
Endomorphism
Another endomorphism!
Partial application of event
• incremental updates
• can handle missing events
Monads vs. monoids?
Series combination
=+
Result is same
kind of thing
(Closure)
Series combination
+
Order not
important
(Associative) Monoid!
+( )
++( )
Parallel combination
=+
Same thing
(Closure)
Order not
important
(Associative)
Monoid!
Monad laws
• The Monad laws are just the monoid
definitions in diguise
– Closure, Associativity, Identity
• What happens if you break the monad laws?
– You go to jail
– You lose monoid benefits such as aggregation
A monad is just a monoid in
the category of endofunctors!
A monad is just a monoid in
the category of endofunctors!
THANKS!

More Related Content

What's hot

Domain Driven Design with the F# type System -- NDC London 2013
Domain Driven Design with the F# type System -- NDC London 2013Domain Driven Design with the F# type System -- NDC London 2013
Domain Driven Design with the F# type System -- NDC London 2013Scott Wlaschin
 
The Functional Programming Triad of Map, Filter and Fold
The Functional Programming Triad of Map, Filter and FoldThe Functional Programming Triad of Map, Filter and Fold
The Functional Programming Triad of Map, Filter and FoldPhilip Schwarz
 
Sum and Product Types - The Fruit Salad & Fruit Snack Example - From F# to Ha...
Sum and Product Types -The Fruit Salad & Fruit Snack Example - From F# to Ha...Sum and Product Types -The Fruit Salad & Fruit Snack Example - From F# to Ha...
Sum and Product Types - The Fruit Salad & Fruit Snack Example - From F# to Ha...Philip Schwarz
 
From object oriented to functional domain modeling
From object oriented to functional domain modelingFrom object oriented to functional domain modeling
From object oriented to functional domain modelingMario Fusco
 
Domain Modeling in a Functional World
Domain Modeling in a Functional WorldDomain Modeling in a Functional World
Domain Modeling in a Functional WorldDebasish Ghosh
 
Functional solid
Functional solidFunctional solid
Functional solidMatt Stine
 
Monad Laws Must be Checked
Monad Laws Must be CheckedMonad Laws Must be Checked
Monad Laws Must be CheckedPhilip Schwarz
 
Blazing Fast, Pure Effects without Monads — LambdaConf 2018
Blazing Fast, Pure Effects without Monads — LambdaConf 2018Blazing Fast, Pure Effects without Monads — LambdaConf 2018
Blazing Fast, Pure Effects without Monads — LambdaConf 2018John De Goes
 
Thirteen ways of looking at a turtle
Thirteen ways of looking at a turtleThirteen ways of looking at a turtle
Thirteen ways of looking at a turtleScott Wlaschin
 
Functional Programming in JavaScript by Luis Atencio
Functional Programming in JavaScript by Luis AtencioFunctional Programming in JavaScript by Luis Atencio
Functional Programming in JavaScript by Luis AtencioLuis Atencio
 
Functional Programming Patterns (BuildStuff '14)
Functional Programming Patterns (BuildStuff '14)Functional Programming Patterns (BuildStuff '14)
Functional Programming Patterns (BuildStuff '14)Scott Wlaschin
 
Designing with Capabilities
Designing with CapabilitiesDesigning with Capabilities
Designing with CapabilitiesScott Wlaschin
 
Functional Domain Modeling - The ZIO 2 Way
Functional Domain Modeling - The ZIO 2 WayFunctional Domain Modeling - The ZIO 2 Way
Functional Domain Modeling - The ZIO 2 WayDebasish Ghosh
 
Enterprise Tic-Tac-Toe
Enterprise Tic-Tac-ToeEnterprise Tic-Tac-Toe
Enterprise Tic-Tac-ToeScott Wlaschin
 
Dr Frankenfunctor and the Monadster
Dr Frankenfunctor and the MonadsterDr Frankenfunctor and the Monadster
Dr Frankenfunctor and the MonadsterScott Wlaschin
 

What's hot (20)

Domain Driven Design with the F# type System -- NDC London 2013
Domain Driven Design with the F# type System -- NDC London 2013Domain Driven Design with the F# type System -- NDC London 2013
Domain Driven Design with the F# type System -- NDC London 2013
 
The Functional Programming Triad of Map, Filter and Fold
The Functional Programming Triad of Map, Filter and FoldThe Functional Programming Triad of Map, Filter and Fold
The Functional Programming Triad of Map, Filter and Fold
 
Sum and Product Types - The Fruit Salad & Fruit Snack Example - From F# to Ha...
Sum and Product Types -The Fruit Salad & Fruit Snack Example - From F# to Ha...Sum and Product Types -The Fruit Salad & Fruit Snack Example - From F# to Ha...
Sum and Product Types - The Fruit Salad & Fruit Snack Example - From F# to Ha...
 
From object oriented to functional domain modeling
From object oriented to functional domain modelingFrom object oriented to functional domain modeling
From object oriented to functional domain modeling
 
Domain Modeling in a Functional World
Domain Modeling in a Functional WorldDomain Modeling in a Functional World
Domain Modeling in a Functional World
 
Functional solid
Functional solidFunctional solid
Functional solid
 
Monad Laws Must be Checked
Monad Laws Must be CheckedMonad Laws Must be Checked
Monad Laws Must be Checked
 
Blazing Fast, Pure Effects without Monads — LambdaConf 2018
Blazing Fast, Pure Effects without Monads — LambdaConf 2018Blazing Fast, Pure Effects without Monads — LambdaConf 2018
Blazing Fast, Pure Effects without Monads — LambdaConf 2018
 
Thirteen ways of looking at a turtle
Thirteen ways of looking at a turtleThirteen ways of looking at a turtle
Thirteen ways of looking at a turtle
 
Clean code slide
Clean code slideClean code slide
Clean code slide
 
Functional Programming in JavaScript by Luis Atencio
Functional Programming in JavaScript by Luis AtencioFunctional Programming in JavaScript by Luis Atencio
Functional Programming in JavaScript by Luis Atencio
 
Python Programming Essentials - M27 - Logging module
Python Programming Essentials - M27 - Logging modulePython Programming Essentials - M27 - Logging module
Python Programming Essentials - M27 - Logging module
 
Functional Programming Patterns (BuildStuff '14)
Functional Programming Patterns (BuildStuff '14)Functional Programming Patterns (BuildStuff '14)
Functional Programming Patterns (BuildStuff '14)
 
Designing with Capabilities
Designing with CapabilitiesDesigning with Capabilities
Designing with Capabilities
 
F# for C# Programmers
F# for C# ProgrammersF# for C# Programmers
F# for C# Programmers
 
Functional Domain Modeling - The ZIO 2 Way
Functional Domain Modeling - The ZIO 2 WayFunctional Domain Modeling - The ZIO 2 Way
Functional Domain Modeling - The ZIO 2 Way
 
Java 8 Workshop
Java 8 WorkshopJava 8 Workshop
Java 8 Workshop
 
Enterprise Tic-Tac-Toe
Enterprise Tic-Tac-ToeEnterprise Tic-Tac-Toe
Enterprise Tic-Tac-Toe
 
Clean coding-practices
Clean coding-practicesClean coding-practices
Clean coding-practices
 
Dr Frankenfunctor and the Monadster
Dr Frankenfunctor and the MonadsterDr Frankenfunctor and the Monadster
Dr Frankenfunctor and the Monadster
 

Similar to Functional Programming Patterns (NDC London 2014)

Functors, applicatives, monads
Functors, applicatives, monadsFunctors, applicatives, monads
Functors, applicatives, monadsrkaippully
 
Functional programming with haskell
Functional programming with haskellFunctional programming with haskell
Functional programming with haskellfaradjpour
 
Twins: Object Oriented Programming and Functional Programming
Twins: Object Oriented Programming and Functional ProgrammingTwins: Object Oriented Programming and Functional Programming
Twins: Object Oriented Programming and Functional ProgrammingRichardWarburton
 
掀起 Swift 的面紗
掀起 Swift 的面紗掀起 Swift 的面紗
掀起 Swift 的面紗Pofat Tseng
 
SeneJug java_8_prez_122015
SeneJug java_8_prez_122015SeneJug java_8_prez_122015
SeneJug java_8_prez_122015senejug
 
Cluj.py Meetup: Extending Python in C
Cluj.py Meetup: Extending Python in CCluj.py Meetup: Extending Python in C
Cluj.py Meetup: Extending Python in CSteffen Wenz
 
Kotlin as a Better Java
Kotlin as a Better JavaKotlin as a Better Java
Kotlin as a Better JavaGarth Gilmour
 
How to start functional programming (in Scala): Day1
How to start functional programming (in Scala): Day1How to start functional programming (in Scala): Day1
How to start functional programming (in Scala): Day1Taisuke Oe
 
Let the type system be your friend
Let the type system be your friendLet the type system be your friend
Let the type system be your friendThe Software House
 
Use Applicative where applicable!
Use Applicative where applicable!Use Applicative where applicable!
Use Applicative where applicable!Hermann Hueck
 
how to reuse code
how to reuse codehow to reuse code
how to reuse codejleed1
 
C++ Course - Lesson 2
C++ Course - Lesson 2C++ Course - Lesson 2
C++ Course - Lesson 2Mohamed Ahmed
 
An introduction to property based testing
An introduction to property based testingAn introduction to property based testing
An introduction to property based testingScott Wlaschin
 
Towards Programming Languages for Reasoning.pptx
Towards Programming Languages for Reasoning.pptxTowards Programming Languages for Reasoning.pptx
Towards Programming Languages for Reasoning.pptxmarkmarron7
 
Thinking in Functions: Functional Programming in Python
Thinking in Functions: Functional Programming in PythonThinking in Functions: Functional Programming in Python
Thinking in Functions: Functional Programming in PythonAnoop Thomas Mathew
 
Introduction to Kotlin.pptx
Introduction to Kotlin.pptxIntroduction to Kotlin.pptx
Introduction to Kotlin.pptxAzharFauzan9
 
01 Introduction to Kotlin - Programming in Kotlin.pptx
01 Introduction to Kotlin - Programming in Kotlin.pptx01 Introduction to Kotlin - Programming in Kotlin.pptx
01 Introduction to Kotlin - Programming in Kotlin.pptxIvanZawPhyo
 
Why Haskell Matters
Why Haskell MattersWhy Haskell Matters
Why Haskell Mattersromanandreg
 

Similar to Functional Programming Patterns (NDC London 2014) (20)

Functors, applicatives, monads
Functors, applicatives, monadsFunctors, applicatives, monads
Functors, applicatives, monads
 
Monads in Swift
Monads in SwiftMonads in Swift
Monads in Swift
 
Functional programming with haskell
Functional programming with haskellFunctional programming with haskell
Functional programming with haskell
 
Twins: Object Oriented Programming and Functional Programming
Twins: Object Oriented Programming and Functional ProgrammingTwins: Object Oriented Programming and Functional Programming
Twins: Object Oriented Programming and Functional Programming
 
掀起 Swift 的面紗
掀起 Swift 的面紗掀起 Swift 的面紗
掀起 Swift 的面紗
 
SeneJug java_8_prez_122015
SeneJug java_8_prez_122015SeneJug java_8_prez_122015
SeneJug java_8_prez_122015
 
Cluj.py Meetup: Extending Python in C
Cluj.py Meetup: Extending Python in CCluj.py Meetup: Extending Python in C
Cluj.py Meetup: Extending Python in C
 
Kotlin as a Better Java
Kotlin as a Better JavaKotlin as a Better Java
Kotlin as a Better Java
 
How to start functional programming (in Scala): Day1
How to start functional programming (in Scala): Day1How to start functional programming (in Scala): Day1
How to start functional programming (in Scala): Day1
 
functions
functionsfunctions
functions
 
Let the type system be your friend
Let the type system be your friendLet the type system be your friend
Let the type system be your friend
 
Use Applicative where applicable!
Use Applicative where applicable!Use Applicative where applicable!
Use Applicative where applicable!
 
how to reuse code
how to reuse codehow to reuse code
how to reuse code
 
C++ Course - Lesson 2
C++ Course - Lesson 2C++ Course - Lesson 2
C++ Course - Lesson 2
 
An introduction to property based testing
An introduction to property based testingAn introduction to property based testing
An introduction to property based testing
 
Towards Programming Languages for Reasoning.pptx
Towards Programming Languages for Reasoning.pptxTowards Programming Languages for Reasoning.pptx
Towards Programming Languages for Reasoning.pptx
 
Thinking in Functions: Functional Programming in Python
Thinking in Functions: Functional Programming in PythonThinking in Functions: Functional Programming in Python
Thinking in Functions: Functional Programming in Python
 
Introduction to Kotlin.pptx
Introduction to Kotlin.pptxIntroduction to Kotlin.pptx
Introduction to Kotlin.pptx
 
01 Introduction to Kotlin - Programming in Kotlin.pptx
01 Introduction to Kotlin - Programming in Kotlin.pptx01 Introduction to Kotlin - Programming in Kotlin.pptx
01 Introduction to Kotlin - Programming in Kotlin.pptx
 
Why Haskell Matters
Why Haskell MattersWhy Haskell Matters
Why Haskell Matters
 

More from Scott Wlaschin

Domain Modeling Made Functional (DevTernity 2022)
Domain Modeling Made Functional (DevTernity 2022)Domain Modeling Made Functional (DevTernity 2022)
Domain Modeling Made Functional (DevTernity 2022)Scott Wlaschin
 
Pipeline oriented programming
Pipeline oriented programmingPipeline oriented programming
Pipeline oriented programmingScott Wlaschin
 
Building confidence in concurrent code with a model checker: TLA+ for program...
Building confidence in concurrent code with a model checker: TLA+ for program...Building confidence in concurrent code with a model checker: TLA+ for program...
Building confidence in concurrent code with a model checker: TLA+ for program...Scott Wlaschin
 
Domain Modeling with FP (DDD Europe 2020)
Domain Modeling with FP (DDD Europe 2020)Domain Modeling with FP (DDD Europe 2020)
Domain Modeling with FP (DDD Europe 2020)Scott Wlaschin
 
Reinventing the Transaction Script (NDC London 2020)
Reinventing the Transaction Script (NDC London 2020)Reinventing the Transaction Script (NDC London 2020)
Reinventing the Transaction Script (NDC London 2020)Scott Wlaschin
 
Domain Modeling Made Functional (KanDDDinsky 2019)
Domain Modeling Made Functional (KanDDDinsky 2019)Domain Modeling Made Functional (KanDDDinsky 2019)
Domain Modeling Made Functional (KanDDDinsky 2019)Scott Wlaschin
 
Four Languages From Forty Years Ago (NewCrafts 2019)
Four Languages From Forty Years Ago (NewCrafts 2019)Four Languages From Forty Years Ago (NewCrafts 2019)
Four Languages From Forty Years Ago (NewCrafts 2019)Scott Wlaschin
 
Four Languages From Forty Years Ago
Four Languages From Forty Years AgoFour Languages From Forty Years Ago
Four Languages From Forty Years AgoScott Wlaschin
 
Designing with capabilities (DDD-EU 2017)
Designing with capabilities (DDD-EU 2017)Designing with capabilities (DDD-EU 2017)
Designing with capabilities (DDD-EU 2017)Scott Wlaschin
 
Railway Oriented Programming
Railway Oriented ProgrammingRailway Oriented Programming
Railway Oriented ProgrammingScott Wlaschin
 

More from Scott Wlaschin (13)

Domain Modeling Made Functional (DevTernity 2022)
Domain Modeling Made Functional (DevTernity 2022)Domain Modeling Made Functional (DevTernity 2022)
Domain Modeling Made Functional (DevTernity 2022)
 
Pipeline oriented programming
Pipeline oriented programmingPipeline oriented programming
Pipeline oriented programming
 
Building confidence in concurrent code with a model checker: TLA+ for program...
Building confidence in concurrent code with a model checker: TLA+ for program...Building confidence in concurrent code with a model checker: TLA+ for program...
Building confidence in concurrent code with a model checker: TLA+ for program...
 
Domain Modeling with FP (DDD Europe 2020)
Domain Modeling with FP (DDD Europe 2020)Domain Modeling with FP (DDD Europe 2020)
Domain Modeling with FP (DDD Europe 2020)
 
Reinventing the Transaction Script (NDC London 2020)
Reinventing the Transaction Script (NDC London 2020)Reinventing the Transaction Script (NDC London 2020)
Reinventing the Transaction Script (NDC London 2020)
 
Domain Modeling Made Functional (KanDDDinsky 2019)
Domain Modeling Made Functional (KanDDDinsky 2019)Domain Modeling Made Functional (KanDDDinsky 2019)
Domain Modeling Made Functional (KanDDDinsky 2019)
 
Four Languages From Forty Years Ago (NewCrafts 2019)
Four Languages From Forty Years Ago (NewCrafts 2019)Four Languages From Forty Years Ago (NewCrafts 2019)
Four Languages From Forty Years Ago (NewCrafts 2019)
 
Four Languages From Forty Years Ago
Four Languages From Forty Years AgoFour Languages From Forty Years Ago
Four Languages From Forty Years Ago
 
Designing with capabilities (DDD-EU 2017)
Designing with capabilities (DDD-EU 2017)Designing with capabilities (DDD-EU 2017)
Designing with capabilities (DDD-EU 2017)
 
Swift vs. Language X
Swift vs. Language XSwift vs. Language X
Swift vs. Language X
 
Doge-driven design
Doge-driven designDoge-driven design
Doge-driven design
 
Railway Oriented Programming
Railway Oriented ProgrammingRailway Oriented Programming
Railway Oriented Programming
 
The Theory of Chains
The Theory of ChainsThe Theory of Chains
The Theory of Chains
 

Recently uploaded

办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样umasea
 
SensoDat: Simulation-based Sensor Dataset of Self-driving Cars
SensoDat: Simulation-based Sensor Dataset of Self-driving CarsSensoDat: Simulation-based Sensor Dataset of Self-driving Cars
SensoDat: Simulation-based Sensor Dataset of Self-driving CarsChristian Birchler
 
Unveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML DiagramsUnveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML DiagramsAhmed Mohamed
 
Unveiling the Future: Sylius 2.0 New Features
Unveiling the Future: Sylius 2.0 New FeaturesUnveiling the Future: Sylius 2.0 New Features
Unveiling the Future: Sylius 2.0 New FeaturesŁukasz Chruściel
 
Balasore Best It Company|| Top 10 IT Company || Balasore Software company Odisha
Balasore Best It Company|| Top 10 IT Company || Balasore Software company OdishaBalasore Best It Company|| Top 10 IT Company || Balasore Software company Odisha
Balasore Best It Company|| Top 10 IT Company || Balasore Software company Odishasmiwainfosol
 
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte Germany
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte GermanySuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte Germany
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte GermanyChristoph Pohl
 
React Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief UtamaReact Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief UtamaHanief Utama
 
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptxKnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptxTier1 app
 
Implementing Zero Trust strategy with Azure
Implementing Zero Trust strategy with AzureImplementing Zero Trust strategy with Azure
Implementing Zero Trust strategy with AzureDinusha Kumarasiri
 
Software Coding for software engineering
Software Coding for software engineeringSoftware Coding for software engineering
Software Coding for software engineeringssuserb3a23b
 
A healthy diet for your Java application Devoxx France.pdf
A healthy diet for your Java application Devoxx France.pdfA healthy diet for your Java application Devoxx France.pdf
A healthy diet for your Java application Devoxx France.pdfMarharyta Nedzelska
 
Introduction Computer Science - Software Design.pdf
Introduction Computer Science - Software Design.pdfIntroduction Computer Science - Software Design.pdf
Introduction Computer Science - Software Design.pdfFerryKemperman
 
How to submit a standout Adobe Champion Application
How to submit a standout Adobe Champion ApplicationHow to submit a standout Adobe Champion Application
How to submit a standout Adobe Champion ApplicationBradBedford3
 
Ahmed Motair CV April 2024 (Senior SW Developer)
Ahmed Motair CV April 2024 (Senior SW Developer)Ahmed Motair CV April 2024 (Senior SW Developer)
Ahmed Motair CV April 2024 (Senior SW Developer)Ahmed Mater
 
Exploring Selenium_Appium Frameworks for Seamless Integration with HeadSpin.pdf
Exploring Selenium_Appium Frameworks for Seamless Integration with HeadSpin.pdfExploring Selenium_Appium Frameworks for Seamless Integration with HeadSpin.pdf
Exploring Selenium_Appium Frameworks for Seamless Integration with HeadSpin.pdfkalichargn70th171
 
Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...
Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...
Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...OnePlan Solutions
 
MYjobs Presentation Django-based project
MYjobs Presentation Django-based projectMYjobs Presentation Django-based project
MYjobs Presentation Django-based projectAnoyGreter
 
Recruitment Management Software Benefits (Infographic)
Recruitment Management Software Benefits (Infographic)Recruitment Management Software Benefits (Infographic)
Recruitment Management Software Benefits (Infographic)Hr365.us smith
 

Recently uploaded (20)

办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样
 
SensoDat: Simulation-based Sensor Dataset of Self-driving Cars
SensoDat: Simulation-based Sensor Dataset of Self-driving CarsSensoDat: Simulation-based Sensor Dataset of Self-driving Cars
SensoDat: Simulation-based Sensor Dataset of Self-driving Cars
 
Unveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML DiagramsUnveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML Diagrams
 
Unveiling the Future: Sylius 2.0 New Features
Unveiling the Future: Sylius 2.0 New FeaturesUnveiling the Future: Sylius 2.0 New Features
Unveiling the Future: Sylius 2.0 New Features
 
Balasore Best It Company|| Top 10 IT Company || Balasore Software company Odisha
Balasore Best It Company|| Top 10 IT Company || Balasore Software company OdishaBalasore Best It Company|| Top 10 IT Company || Balasore Software company Odisha
Balasore Best It Company|| Top 10 IT Company || Balasore Software company Odisha
 
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte Germany
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte GermanySuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte Germany
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte Germany
 
React Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief UtamaReact Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief Utama
 
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptxKnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
 
Implementing Zero Trust strategy with Azure
Implementing Zero Trust strategy with AzureImplementing Zero Trust strategy with Azure
Implementing Zero Trust strategy with Azure
 
Software Coding for software engineering
Software Coding for software engineeringSoftware Coding for software engineering
Software Coding for software engineering
 
A healthy diet for your Java application Devoxx France.pdf
A healthy diet for your Java application Devoxx France.pdfA healthy diet for your Java application Devoxx France.pdf
A healthy diet for your Java application Devoxx France.pdf
 
Introduction Computer Science - Software Design.pdf
Introduction Computer Science - Software Design.pdfIntroduction Computer Science - Software Design.pdf
Introduction Computer Science - Software Design.pdf
 
How to submit a standout Adobe Champion Application
How to submit a standout Adobe Champion ApplicationHow to submit a standout Adobe Champion Application
How to submit a standout Adobe Champion Application
 
Ahmed Motair CV April 2024 (Senior SW Developer)
Ahmed Motair CV April 2024 (Senior SW Developer)Ahmed Motair CV April 2024 (Senior SW Developer)
Ahmed Motair CV April 2024 (Senior SW Developer)
 
Odoo Development Company in India | Devintelle Consulting Service
Odoo Development Company in India | Devintelle Consulting ServiceOdoo Development Company in India | Devintelle Consulting Service
Odoo Development Company in India | Devintelle Consulting Service
 
Exploring Selenium_Appium Frameworks for Seamless Integration with HeadSpin.pdf
Exploring Selenium_Appium Frameworks for Seamless Integration with HeadSpin.pdfExploring Selenium_Appium Frameworks for Seamless Integration with HeadSpin.pdf
Exploring Selenium_Appium Frameworks for Seamless Integration with HeadSpin.pdf
 
Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...
Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...
Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...
 
MYjobs Presentation Django-based project
MYjobs Presentation Django-based projectMYjobs Presentation Django-based project
MYjobs Presentation Django-based project
 
Recruitment Management Software Benefits (Infographic)
Recruitment Management Software Benefits (Infographic)Recruitment Management Software Benefits (Infographic)
Recruitment Management Software Benefits (Infographic)
 
Hot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort Service
Hot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort ServiceHot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort Service
Hot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort Service
 

Functional Programming Patterns (NDC London 2014)

  • 1. Functional Design Patterns (NDC London 2014) @ScottWlaschin fsharpforfunandprofit.com
  • 4. HOW I GOT HERE
  • 5. Me
  • 6. I
  • 7. Making fun of Enterprise OO is like shooting fish in a barrel I but...
  • 8. I but... Making fun of Enterprise OO is like shooting IMarineVertebrates in an AbstractBarrelProxyFactory Inspired by @sjkilleen
  • 9. I
  • 10. This is what happens when you dabble too much in functional programming
  • 13. • Single Responsibility Principle • Open/Closed principle • Dependency Inversion Principle • Interface Segregation Principle • Factory pattern • Strategy pattern • Decorator pattern • Visitor pattern OO pattern/principle
  • 14. • Single Responsibility Principle • Open/Closed principle • Dependency Inversion Principle • Interface Segregation Principle • Factory pattern • Strategy pattern • Decorator pattern • Visitor pattern OO pattern/principle Borg response
  • 15. • Single Responsibility Principle • Open/Closed principle • Dependency Inversion Principle • Interface Segregation Principle • Factory pattern • Strategy pattern • Decorator pattern • Visitor pattern • Functions • Functions • Functions, also • Functions • You will be assimilated! • Functions again • Functions • Resistance is futile! OO pattern/principle FP equivalent Seriously, FP patterns are different
  • 16. Functional patterns • Apomorphisms • Dynamorphisms • Chronomorphisms • Zygohistomorphic prepromorphisms
  • 17. Functional patterns • Core Principles of FP design – Functions, types, composition • Functions as parameters – Functions as interfaces – Partial application & dependency injection – Continuations, chaining & the pyramid of doom • Monads – Error handling, Async • Maps – Dealing with wrapped data – Functors • Monoids – Aggregating data and operations
  • 18. This talk A whirlwind tour of many sights Don't worry if you don't understand everything
  • 19. (SOME) CORE PRINCIPLES OF FUNCTIONAL PROGRAMMING Important to understand!
  • 20. Core principles of FP Function Types are not classes Functions are things Composition everywhere
  • 21. Core principle: Functions are things Function
  • 22. Functions as things The Tunnel of Transformation Function apple -> banana A function is a standalone thing, not attached to a class
  • 23. Functions as things let z = 1 int-> int->int 1 let add x y = x + y
  • 24. Functions as inputs and outputs let useFn f = (f 1) + 2 let add x = (fun y -> x + y) int->(int->int) int int let transformInt f x = (f x) + 1 int int int->int Function as output Int ->int Function as input Function as parameterint->int (int->int)->int int->int
  • 26. Function composition Function 1 apple -> banana Function 2 banana -> cherry
  • 27. Function composition >> Function 1 apple -> banana Function 2 banana -> cherry
  • 28. Function composition New Function apple -> cherry Can't tell it was built from smaller functions!
  • 30. “Functions in the small, objects in the large”
  • 32. Low-level operation Service AddressValidator A “Service” is just like a microservice but without the "micro" in front Validation Result Address Low-level operation Low-level operation
  • 36. X
  • 37. Types are not classes Set of valid inputs Set of valid outputs So what is a type?
  • 38. Types separate data from behavior Lists Lists List.map List.collect List.filter List.etc
  • 39. Types can be composed too “algebraic types"
  • 40. Product types × = Alice, Jan 12th Bob, Feb 2nd Carol, Mar 3rd Set of people Set of dates type Birthday = Person * Date
  • 41. Sum types Set of Cash values Set of Cheque values Set of CreditCard values + + type PaymentMethod = | Cash | Cheque of ChequeNumber | Card of CardType * CardNumber
  • 43. twelveDividedBy(x) input x maps to 12/x … 3 2 1 0 … Domain (int) Codomain (int) … 4 6 12 … Totality int TwelveDividedBy(int input) { switch (input) { case 3: return 4; case 2: return 6; case 1: return 12; case 0: return ??; } }
  • 44. twelveDividedBy(x) input x maps to 12/x … 3 2 1 0 … Domain (int) Codomain (int) … 4 6 12 … Totality int TwelveDividedBy(int input) { switch (input) { case 3: return 4; case 2: return 6; case 1: return 12; case 0: return ??; } } What happens here?
  • 45. twelveDividedBy(x) input x maps to 12/x … 3 2 1 0 … Domain (int) Codomain (int) … 4 6 12 … Totality int TwelveDividedBy(int input) { switch (input) { case 3: return 4; case 2: return 6; case 1: return 12; case 0: throw InvalidArgException; } } int -> int This type signature is a lie! You tell me you can handle 0, and then you complain about it?
  • 46. twelveDividedBy(x) input x maps to 12/x … 3 2 1 -1 … NonZeroInteger int … 4 6 12 … Totality int TwelveDividedBy(int input) { switch (input) { case 3: return 4; case 2: return 6; case 1: return 12; case -1: return -12; } } Constrain the input 0 doesn’t have to be handled NonZeroInteger -> int 0 is missing Types are documentation
  • 47. twelveDividedBy(x) input x maps to 12/x … 3 2 1 0 -1 … int Option<Int> … Some 4 Some 6 Some 12 None … Totality int TwelveDividedBy(int input) { switch (input) { case 3: return Some 4; case 2: return Some 6; case 1: return Some 12; case 0: return None; } } Extend the output 0 is valid input int -> int option Types are documentation
  • 48. Design principle: Use static types for domain modelling and documentation Static types only! Sorry Clojure and JS developers 
  • 49. Big topic! Not enough time today ! More on DDD and designing with types at fsharpforfunandprofit.com/ddd
  • 52. Parameterize all the things let printList() = for i in [1..10] do printfn "the number is %i" i
  • 53. Parameterize all the things It's second nature to parameterize the data input: let printList aList = for i in aList do printfn "the number is %i" i
  • 54. Parameterize all the things let printList anAction aList = for i in aList do anAction i FPers would parameterize the action as well: We've decoupled the behavior from the data. Any list, any action!
  • 55. Parameterize all the things public static int Product(int n) { int product = 1; for (int i = 1; i <= n; i++) { product *= i; } return product; } public static int Sum(int n) { int sum = 0; for (int i = 1; i <= n; i++) { sum += i; } return sum; }
  • 56. public static int Product(int n) { int product = 1; for (int i = 1; i <= n; i++) { product *= i; } return product; } public static int Sum(int n) { int sum = 0; for (int i = 1; i <= n; i++) { sum += i; } return sum; } Parameterize all the things
  • 57. Parameterize all the things let product n = let initialValue = 1 let action productSoFar x = productSoFar * x [1..n] |> List.fold action initialValue let sum n = let initialValue = 0 let action sumSoFar x = sumSoFar+x [1..n] |> List.fold action initialValue Lots of collection functions like this: "fold", "map", "reduce", "collect", etc.
  • 58. Tip: Function types are "interfaces"
  • 59. Function types are interfaces interface IBunchOfStuff { int DoSomething(int x); string DoSomethingElse(int x); void DoAThirdThing(string x); } Let's take the Single Responsibility Principle and the Interface Segregation Principle to the extreme... Every interface should have only one method!
  • 60. Function types are interfaces interface IBunchOfStuff { int DoSomething(int x); } An interface with one method is a just a function type type IBunchOfStuff: int -> int Any function with that type is compatible with it let add2 x = x + 2 // int -> int let times3 x = x * 3 // int -> int
  • 61. Strategy pattern class MyClass { public MyClass(IBunchOfStuff strategy) {..} int DoSomethingWithStuff(int x) { return _strategy.DoSomething(x) } } Object-oriented strategy pattern:
  • 62. Strategy pattern int int int->int int->int let DoSomethingWithStuff strategy x = strategy x Functional strategy pattern: IBunchOfStuff as parameter
  • 63. Decorator pattern using function parameter: let isEven x = (x % 2 = 0) // int -> bool isEvenint bool loggerint bool let logger f input = let output = f input // then log input and output // return output
  • 64. Decorator pattern using function parameter: let isEven x = (x % 2 = 0) // int -> bool isEvenint bool loggerint bool let isEvenWithLogging = logger isEven // int -> bool Substitutable for original isEven
  • 65. Decorator pattern using function composition: let isEven x = (x % 2 = 0) // int -> bool isEvenint bool isEvenint boollogint int logbool bool let isEvenWithLogging = log >> isEven >> log // int -> bool Substitutable for original isEven Composition!
  • 66. Bad news: Composition patterns only work for functions that have one parameter! 
  • 67. Good news! Every function is a one parameter function 
  • 68. Writing functions in different ways let add x y = x + y let add = (fun x y -> x + y) let add x = (fun y -> x + y) int-> int->int int-> int->int int-> (int->int) Normal (Two parameters)
  • 69. let three = 1 + 2 let three = (+) 1 2 let three = ((+) 1) 2 "+" is a two parameter function
  • 70. let three = 1 + 2 let three = (+) 1 2 let three = ((+) 1) 2 let add1 = (+) 1 let three = add1 2 No, "+" is a one param function!
  • 72. let name = "Scott" printfn "Hello, my name is %s" name let name = "Scott" (printfn "Hello, my name is %s") name let name = "Scott" let hello = (printfn "Hello, my name is %s") hello name Can reuse "hello" in many places now!
  • 73. Pattern: Use partial application when working with lists
  • 74. let names = ["Alice"; "Bob"; "Scott"] names |> List.iter hello let hello = printfn "Hello, my name is %s" let add1 = (+) 1 let equals2 = (=) 2 [1..100] |> List.map add1 |> List.filter equals2
  • 75. Pattern: Use partial application to do dependency injection
  • 76. type GetCustomer = CustomerId -> Customer let getCustomerFromDatabase connection (customerId:CustomerId) = // from connection // select customer // where customerId = customerId type of getCustomerFromDatabase = DbConnection -> CustomerId -> Customer let getCustomer1 = getCustomerFromDatabase myConnection // getCustomer1 : CustomerId -> Customer Persistence ignorant This function requires a connection  The partially applied function does NOT require a connection – it's baked in! 
  • 77. type GetCustomer = CustomerId -> Customer let getCustomerFromMemory dict (customerId:CustomerId) = dict.Get(customerId) type of getCustomerFromMemory = Dictionary<Id,Customer> -> CustomerId -> Customer let getCustomer2 = getCustomerFromMemory dict // getCustomer2 : CustomerId -> Customer This function requires a dictionary  The partially applied function does NOT require a dictionary – it's baked in! 
  • 79. Continuations int Divide(int top, int bottom) { if (bottom == 0) { throw new InvalidOperationException("div by 0"); } else { return top/bottom; } } Method has decided to throw an exception (who put it in charge?)
  • 80. Continuations void Divide(int top, int bottom, Action ifZero, Action<int> ifSuccess) { if (bottom == 0) { ifZero(); } else { ifSuccess( top/bottom ); } } Let the caller decide what happens what happens next?
  • 81. Continuations let divide ifZero ifSuccess top bottom = if (bottom=0) then ifZero() else ifSuccess (top/bottom) F# version Four parameters is a lot though! Wouldn't it be nice if we could somehow "bake in" the two behaviour functions....
  • 82. Continuations let divide ifZero ifSuccess top bottom = if (bottom=0) then ifZero() else ifSuccess (top/bottom) let ifZero1 () = printfn "bad" let ifSuccess1 x = printfn "good %i" x let divide1 = divide ifZero1 ifSuccess1 //test let good1 = divide1 6 3 let bad1 = divide1 6 0 setup the functions to: print a message Partially apply the continuations Use it like a normal function – only two parameters
  • 83. let divide ifZero ifSuccess top bottom = if (bottom=0) then ifZero() else ifSuccess (top/bottom) Continuations let ifZero2() = None let ifSuccess2 x = Some x let divide2 = divide ifZero2 ifSuccess2 //test let good2 = divide2 6 3 let bad2 = divide2 6 0 setup the functions to: return an Option Use it like a normal function – only two parameters Partially apply the continuations
  • 84. let divide ifZero ifSuccess top bottom = if (bottom=0) then ifZero() else ifSuccess (top/bottom) Continuations let ifZero3() = failwith "div by 0" let ifSuccess3 x = x let divide3 = divide ifZero3 ifSuccess3 //test let good3 = divide3 6 3 let bad3 = divide3 6 0 setup the functions to: throw an exception Use it like a normal function – only two parameters Partially apply the continuations
  • 86. Pyramid of doom: null testing example Let example input = let x = doSomething input if x <> null then let y = doSomethingElse x if y <> null then let z = doAThirdThing y if z <> null then let result = z result else null else null else null I know you could do early returns, but bear with me...
  • 87. Pyramid of doom: async example let taskExample input = let taskX = startTask input taskX.WhenFinished (fun x -> let taskY = startAnotherTask x taskY.WhenFinished (fun y -> let taskZ = startThirdTask y taskZ.WhenFinished (fun z -> z // final result
  • 88. Pyramid of doom: null example let example input = let x = doSomething input if x <> null then let y = doSomethingElse x if y <> null then let z = doAThirdThing y if z <> null then let result = z result else null else null else null Nulls are a code smell: replace with Option!
  • 89. Pyramid of doom: option example let example input = let x = doSomething input if x.IsSome then let y = doSomethingElse (x.Value) if y.IsSome then let z = doAThirdThing (y.Value) if z.IsSome then let result = z.Value Some result else None else None else None Much more elegant, yes? No! This is fugly! But there is a pattern we can exploit...
  • 90. Pyramid of doom: option example let example input = let x = doSomething input if x.IsSome then let y = doSomethingElse (x.Value) if y.IsSome then let z = doAThirdThing (y.Value) if z.IsSome then // do something with z.Value // in this block else None else None else None
  • 91. Pyramid of doom: option example let example input = let x = doSomething input if x.IsSome then let y = doSomethingElse (x.Value) if y.IsSome then // do something with y.Value // in this block else None else None
  • 92. Pyramid of doom: option example let example input = let x = doSomething input if x.IsSome then // do something with x.Value // in this block else None Can you see the pattern?
  • 93. if opt.IsSome then //do something with opt.Value else None
  • 94. let ifSomeDo f opt = if opt.IsSome then f opt.Value else None
  • 95. let example input = doSomething input |> ifSomeDo doSomethingElse |> ifSomeDo doAThirdThing |> ifSomeDo (fun z -> Some z) let ifSomeDo f opt = if opt.IsSome then f opt.Value else None
  • 101. Composing switches >> >> Composing one-track functions is fine...
  • 102. Composing switches >> >> ... and composing two-track functions is fine...
  • 103. Composing switches   ... but composing switches is not allowed!
  • 104. How to combine the mismatched functions?
  • 105. “Bind” is the answer! Bind all the things!
  • 106. Composing switches Two-track input Two-track input One-track input Two-track input  
  • 107. Building an adapter block Two-track input Slot for switch function Two-track output
  • 108. Building an adapter block Two-track input Two-track output
  • 109. let bind nextFunction optionInput = match optionInput with | Some s -> nextFunction s | None -> None Building an adapter block Two-track input Two-track output
  • 110. let bind nextFunction optionInput = match optionInput with | Some s -> nextFunction s | None -> None Building an adapter block Two-track input Two-track output
  • 111. let bind nextFunction optionInput = match optionInput with | Some s -> nextFunction s | None -> None Building an adapter block Two-track input Two-track output
  • 112. let bind nextFunction optionInput = match optionInput with | Some s -> nextFunction s | None -> None Building an adapter block Two-track input Two-track output
  • 113. Pattern: Use bind to chain options
  • 114. Pyramid of doom: using bind let bind f opt = match opt with | Some v -> f v | None -> None let example input = let x = doSomething input if x.IsSome then let y = doSomethingElse (x.Value) if y.IsSome then let z = doAThirdThing (y.Value) if z.IsSome then let result = z.Value Some result else None else None else None
  • 115. let example input = doSomething input |> bind doSomethingElse |> bind doAThirdThing |> bind (fun z -> Some z) Pyramid of doom: using bind Let bind f opt = match opt with | Some v -> f v | None -> None No pyramids! Code is linear and clear. This pattern is called “monadic bind”
  • 116. Pattern: Use bind to chain tasks
  • 118. Pyramid of doom: using bind for tasks let taskBind f task = task.WhenFinished (fun taskResult -> f taskResult) let taskExample input = let taskX = startTask input taskX.WhenFinished (fun x -> let taskY = startAnotherTask x taskY.WhenFinished (fun y -> let taskZ = startThirdTask y taskZ.WhenFinished (fun z -> z // final result a.k.a “promise” “future”
  • 119. Pyramid of doom: using bind for tasks let taskBind f task = task.WhenFinished (fun taskResult -> f taskResult) let taskExample input = startTask input |> taskBind startAnotherTask |> taskBind startThirdTask |> taskBind (fun z -> z) This pattern is also a “monadic bind”
  • 120. Pattern: Use bind to chain error handlers
  • 121. Use case without error handling string UpdateCustomerWithErrorHandling() { var request = receiveRequest(); validateRequest(request); canonicalizeEmail(request); db.updateDbFromRequest(request); smtpServer.sendEmail(request.Email) return "OK"; }
  • 122. Use case with error handling string UpdateCustomerWithErrorHandling() { var request = receiveRequest(); var isValidated = validateRequest(request); if (!isValidated) { return "Request is not valid" } canonicalizeEmail(request); db.updateDbFromRequest(request); smtpServer.sendEmail(request.Email) return "OK"; }
  • 123. Use case with error handling string UpdateCustomerWithErrorHandling() { var request = receiveRequest(); var isValidated = validateRequest(request); if (!isValidated) { return "Request is not valid" } canonicalizeEmail(request); var result = db.updateDbFromRequest(request); if (!result) { return "Customer record not found" } smtpServer.sendEmail(request.Email) return "OK"; }
  • 124. Use case with error handling string UpdateCustomerWithErrorHandling() { var request = receiveRequest(); var isValidated = validateRequest(request); if (!isValidated) { return "Request is not valid" } canonicalizeEmail(request); try { var result = db.updateDbFromRequest(request); if (!result) { return "Customer record not found" } } catch { return "DB error: Customer record not updated" } smtpServer.sendEmail(request.Email) return "OK"; }
  • 125. Use case with error handling string UpdateCustomerWithErrorHandling() { var request = receiveRequest(); var isValidated = validateRequest(request); if (!isValidated) { return "Request is not valid" } canonicalizeEmail(request); try { var result = db.updateDbFromRequest(request); if (!result) { return "Customer record not found" } } catch { return "DB error: Customer record not updated" } if (!smtpServer.sendEmail(request.Email)) { log.Error "Customer email not sent" } return "OK"; }
  • 126. Use case with error handling string UpdateCustomerWithErrorHandling() { var request = receiveRequest(); var isValidated = validateRequest(request); if (!isValidated) { return "Request is not valid" } canonicalizeEmail(request); try { var result = db.updateDbFromRequest(request); if (!result) { return "Customer record not found" } } catch { return "DB error: Customer record not updated" } if (!smtpServer.sendEmail(request.Email)) { log.Error "Customer email not sent" } return "OK"; }
  • 127. A structure for managing errors Request SuccessValidate Failure let validateInput input = if input.name = "" then Failure "Name must not be blank" else if input.email = "" then Failure "Email must not be blank" else Success input // happy path
  • 130. Functional flow without error handling let updateCustomer = receiveRequest |> validateRequest |> canonicalizeEmail |> updateDbFromRequest |> sendEmail |> returnMessage Before One track
  • 131. let updateCustomerWithErrorHandling = receiveRequest |> validateRequest |> canonicalizeEmail |> updateDbFromRequest |> sendEmail |> returnMessage Functional flow with error handling After See my talk on Friday or fsharpforfunandprofit.com/rop Two track
  • 132. MAPS
  • 133. World of normal values int string bool World of options int option string option bool option
  • 134. World of options World of normal values int string bool int option string option bool option 
  • 135. World of options World of normal values int option string option bool option  int string bool
  • 136. let add42ToOption opt = if opt.IsSome then let newVal = add42 opt.Value Some newVal else None How not to code with options Let’s say you have an int wrapped in an Option, and you want to add 42 to it: let add42 x = x + 42 
  • 137. World of options World of normal values add42 
  • 138. World of options World of normal values add42
  • 139. Lifting World of options World of normal values T -> U option<T> -> option<U> Option.map
  • 140. World of options World of normal values add42 add42ToOptionSome 1 |> 1 |> // 43 // Some 43
  • 141. The right way to code with options Let’s say you have an int wrapped in an Option, and you want to add 42 to it: let add42 x = x + 42 1 |> add42 // 43 let add42ToOption = Option.map add42 Some 1 |> add42ToOption // Some 43 
  • 142. The right way to code with options Let’s say you have an int wrapped in an Option, and you want to add 42 to it: let add42 x = x + 42 1 |> add42 // 43 Some 1 |> Option.map add42 // Some 43 
  • 143. Lifting to lists World of lists World of normal values T -> U List<T> -> List<U> List.map
  • 144. The right way to code with wrapped types [1;2;3] |> List.map add42 // [43;44;45]
  • 145. Lifting to async World of async World of normal values T -> U async<T> -> async<U> Async.map
  • 146. Guideline: Most wrapped generic types have a “map”. Use it!
  • 147. Guideline: If you create your own generic type, create a “map” for it.
  • 150. Thinking like a mathematician 1 + 2 = 3 1 + (2 + 3) = (1 + 2) + 3 1 + 0 = 1 0 + 1 = 1
  • 151. 1 + 2 = 3 Some things A way of combining them
  • 152. 2 x 3 = 6 Some things A way of combining them
  • 153. "a" + "b" = "ab" Some things A way of combining them
  • 154. concat([a],[b]) = [a; b] Some things A way of combining them
  • 155. 1 + 2 1 + 2 + 3 1 + 2 + 3 + 4 Is an integer Is an integer A pairwise operation has become an operation that works on lists!
  • 156. 1 + (2 + 3) = (1 + 2) + 3 Order of combining doesn’t matter 1 + 2 + 3 + 4 (1 + 2) + (3 + 4) ((1 + 2) + 3) + 4 All the same
  • 157. 1 - (2 - 3) = (1 - 2) - 3 Order of combining does matter
  • 158. 1 + 0 = 1 0 + 1 = 1 A special kind of thing that when you combine it with something, just gives you back the original something
  • 159. 42 * 1 = 42 1 * 42 = 42 A special kind of thing that when you combine it with something, just gives you back the original something
  • 160. "" + "hello" = "hello" "hello" + "" = "hello" “Zero” for strings
  • 161. The generalization • You start with a bunch of things, and some way of combining them two at a time. • Rule 1 (Closure):The result of combining two things is always another one of the things. • Rule 2 (Associativity):When combining more than two things, which pairwise combination you do first doesn't matter. • Rule 3 (Identity element):There is a special thing called "zero" such that when you combine any thing with "zero" you get the original thing back. A monoid!
  • 162. • Rule 1 (Closure):The result of combining two things is always another one of the things. • Benefit: converts pairwise operations into operations that work on lists. 1 + 2 + 3 + 4 [ 1; 2; 3; 4 ] |> List.reduce (+)
  • 163. 1 * 2 * 3 * 4 [ 1; 2; 3; 4 ] |> List.reduce (*) • Rule 1 (Closure):The result of combining two things is always another one of the things. • Benefit: converts pairwise operations into operations that work on lists.
  • 164. "a" + "b" + "c" + "d" [ "a"; "b"; "c"; "d" ] |> List.reduce (+) • Rule 1 (Closure):The result of combining two things is always another one of the things. • Benefit: converts pairwise operations into operations that work on lists.
  • 165. • Rule 2 (Associativity):When combining more than two things, which pairwise combination you do first doesn't matter. • Benefit: Divide and conquer, parallelization, and incremental accumulation. 1 + 2 + 3 + 4
  • 166. • Rule 2 (Associativity):When combining more than two things, which pairwise combination you do first doesn't matter. • Benefit: Divide and conquer, parallelization, and incremental accumulation. (1 + 2) (3 + 4) 3 + 7
  • 167. • Rule 2 (Associativity):When combining more than two things, which pairwise combination you do first doesn't matter. • Benefit: Divide and conquer, parallelization, and incremental accumulation. (1 + 2 + 3)
  • 168. • Rule 2 (Associativity):When combining more than two things, which pairwise combination you do first doesn't matter. • Benefit: Divide and conquer, parallelization, and incremental accumulation. (1 + 2 + 3) + 4
  • 169. • Rule 2 (Associativity):When combining more than two things, which pairwise combination you do first doesn't matter. • Benefit: Divide and conquer, parallelization, and incremental accumulation. (6) + 4
  • 170. Issues with reduce • How can I use reduce on an empty list? • In a divide and conquer algorithm, what should I do if one of the "divide" steps has nothing in it? • When using an incremental algorithm, what value should I start with when I have no data?
  • 171. • Rule 3 (Identity element):There is a special thing called "zero" such that when you combine any thing with "zero" you get the original thing back. • Benefit: Initial value for empty or missing data
  • 173. type OrderLine = {Qty:int; Total:float} let orderLines = [ {Qty=2; Total=19.98} {Qty=1; Total= 1.99} {Qty=3; Total= 3.99} ] let addPair line1 line2 = let newQty = line1.Qty + line2.Qty let newTotal = line1.Total + line2.Total {Qty=newQty; Total=newTotal} orderLines |> List.reduce addPair // {Qty=6; Total= 25.96} Any combination of monoids is also a monoid Write a pairwise combiner Profit!
  • 175. Customer + Customer + Customer Customer Stats + Customer Stats + Customer Stats Reduce Map Not a monoid A monoid Customer Stats (Total)
  • 176. Hadoop make me a sandwich https://twitter.com/daviottenheimer /status/532661754820829185
  • 178. Log file (Mon) + Log File (Tue) + Log File (Wed) = Really big file Summary (Mon) + Summary (Tue) + Summary (Wed) Map Strings are monoids A monoid Much more efficient for incremental updates “Monoid homomorphism”
  • 180. Monoids in the real world Metrics guideline: Use counters rather than rates Alternative metrics guideline: Make sure your metrics are monoids • incremental updates • can handle missing data
  • 181. Is function composition a monoid? >> Function 1 apple -> banana Function 2 banana -> cherry New Function apple -> cherry Not the same thing. Not a monoid 
  • 182. Is function composition a monoid? >> Function 1 apple -> apple Same thing Function 2 apple -> apple Function 3 apple -> apple A monoid! 
  • 183. Is function composition a monoid? “Functions with same type of input and output” Functions where the input and output are the same type are monoids! What shall we call these kinds of functions?
  • 184. Is function composition a monoid? “Functions with same type of input and output” “Endomorphisms” Functions where the input and output are the same type are monoids! What shall we call these kinds of functions? All endomorphisms are monoids
  • 185. let plus1 x = x + 1 // int->int let times2 x = x * 2 // int->int let subtract42 x = x – 42 // int->int Reduce plus1ThenTimes2ThenSubtract42 // int->int Endomorphisms Another endomorphism!
  • 186. Event sourcing Any function containing an endomorphism can be converted into a monoid! Event application function: Is an endomorphism Event -> State -> State
  • 187. apply event1 // State -> State apply event2 // State -> State apply event3 // State -> State Reduce applyAllEventsAtOnce // State -> State Endomorphism Another endomorphism! Partial application of event • incremental updates • can handle missing events
  • 189. Series combination =+ Result is same kind of thing (Closure)
  • 191. Parallel combination =+ Same thing (Closure) Order not important (Associative) Monoid!
  • 192. Monad laws • The Monad laws are just the monoid definitions in diguise – Closure, Associativity, Identity • What happens if you break the monad laws? – You go to jail – You lose monoid benefits such as aggregation
  • 193. A monad is just a monoid in the category of endofunctors!
  • 194. A monad is just a monoid in the category of endofunctors!