SlideShare a Scribd company logo
1 of 191
Download to read offline
The Power Of Composition
NDC Oslo 2020
@ScottWlaschin
fsharpforfunandprofit.com
The Power Of Composition
1. The philosophy of composition
2. Ideas of functional programming
– Functions and how to compose them
– Types and how to compose them
3. Composition in practice
– Roman Numerals
– FizzBuzz gone functional
– Uh oh, monads!
– A web service
THE PHILOSOPHY OF
COMPOSITION
Prerequisites for
understanding composition
• You must have been a child at some point
• You must have played with Lego
• You must have played with toy trains
Lego
Philosophy
Lego Philosophy
1. All pieces are designed to be connected
2. The pieces are reusable in many contexts
3. Connect two pieces together and get
another "piece" that can still be connected
All pieces are designed to be connected
The pieces are reusable in different contexts
Connect two pieces together and
get another "piece" that can still be connected
Make big things from small things in the same way
Wooden Railway Track Philosophy
1. All pieces are designed to be connected
2. The pieces are reusable in many contexts
3. Connect two pieces together and get
another "piece" that can still be connected
All pieces are designed to be connected
The pieces are reusable in different contexts
Connect two pieces together and get
another "piece" that can still be connected
You can keep adding and adding.
Make big things from small things in the same way
If you understand Lego and wooden
railways, then you know
everything about composition!
THE IDEAS OF
FUNCTIONAL PROGRAMMING
Four ideas behind FP
Function
3.Types are not classes
1. Functions are things
2. Build bigger functions using
composition
4. Build bigger types using
composition
FP idea #1:
Functions are things
Function
The Tunnel of
Transformation
Function
apple -> banana
A function is a thing which
transforms inputs to outputs
A function is a standalone thing,
not attached to a class
A function is a standalone thing,
not attached to a class
It can be used for inputs and outputs
of other functions
A function can be an output thing
input
output
A function can be an input thing
input output
A function can be a parameter
input
output
input output
FP idea #2:
Build bigger functions
using composition
Function 1
apple -> banana
Function 2
banana -> cherry
>>
Function 1
apple -> banana
Function 2
banana -> cherry
New Function
apple -> cherry
Can't tell it was built
from smaller functions!
Where did the banana go?
Function composition in F# and C#
using the "piping" approach
int add1(int x) => x + 1;
int times2(int x) => x * 2;
int square(int x) => x * x;
add1(5); // = 6
times2(add1(5)); // = 12
square(times2(add1(5))); // = 144
Nested function calls
can be confusing if too deep
add15 6 times2 12 square 144
5 |> add1 // = 6
5 |> add1 |> times2 // = 12
5 |> add1 |> times2 |> square // = 144
add1 times2 square5 6 12 144
F# example
add1 times2 square5 6 12 144
5.Pipe(add1);
5.Pipe(add1).Pipe(times2);
5.Pipe(add1).Pipe(times2).Pipe(square);
C# example
Building big things from functions
It's compositions all the way up
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
Http
Response
Http
Request
Even for complex applications,
data flows only in one direction
FP idea #3:
Types are not classes
So, what is a type then?
A type is a just a name
for a set of things
Set of
valid inputs
Set of
valid outputs
Function
Set of
valid inputs
Set of
valid outputs
Function
1
2
3
4
5
6
This is type
"integer"
A type is a just a name
for a set of things
Set of
valid inputs
Set of
valid outputs
Function
This is type
"string"
"abc"
"but"
"cobol"
"double"
"end"
"float"
A type is a just a name
for a set of things
Set of
valid inputs
Set of
valid outputs
Function
This is type
"Person"
Donna Roy
Javier Mendoza
Nathan Logan
Shawna Ingram
Abel Ortiz
Lena Robbins
GordonWood
A type is a just a name
for a set of things
Set of
valid inputs
Set of
valid outputs
Function
This is type
"Fruit"
A type is a just a name
for a set of things
Set of
valid inputs
Set of
valid outputs
Function
This is a type of
Fruit->Fruit functions
A type is a just a name
for a set of things
FP idea #4:
Types can be composed too
Algebraic type system
Bigger types are built from smaller types by:
Composing with “AND”
Composing with “OR”
FruitSalad =
AND AND
Compose with “AND”
Compose with “AND”
enum AppleVariety { Red, Green }
enum BananaVariety { Yellow, Brown }
enum CherryVariety { Tart, Sweet }
struct FruitSalad
{
AppleVariety Apple;
BananaVariety Banana;
CherryVariety Cherry;
}
C# example
Apple AND
Banana AND
Cherry
Compose with “AND”
type AppleVariety = Red | Green
type BananaVariety = Yellow | Brown
type CherryVariety = Tart | Sweet
type FruitSalad = {
Apple: AppleVariety
Banana: BananaVariety
Cherry: CherryVariety
}
F# example
Snack = OR OR
Compose with “OR”
type Snack =
| Apple of AppleVariety
| Banana of BananaVariety
| Cherry of CherryVariety
A real world example
of composing types
Some requirements:
We accept three forms of payment:
Cash, Paypal, or CreditCard.
For Cash we don't need any extra information
For Paypal we need an email address
For Cards we need a card type and card number
interface IPaymentMethod
{..}
class Cash() : IPaymentMethod
{..}
class Paypal(string emailAddress): IPaymentMethod
{..}
class Card(string cardType, string cardNo) : IPaymentMethod
{..}
In OO design you would probably implement it as an
interface and a set of subclasses, like this:
type EmailAddress = string
type CardNumber = string
In F# you would probably implement by composing
types, like this:
type EmailAddress = ...
type CardNumber = …
type CardType = Visa | Mastercard
type CreditCardInfo = {
CardType : CardType
CardNumber : CardNumber
}
type EmailAddress = ...
type CardNumber = ...
type CardType = ...
type CreditCardInfo = ...
type PaymentMethod =
| Cash
| PayPal of EmailAddress
| Card of CreditCardInfo
type EmailAddress = ...
type CardNumber = ...
type CardType = ...
type CreditCardInfo = ...
type PaymentMethod =
| Cash
| PayPal of EmailAddress
| Card of CreditCardInfo
type PaymentAmount = decimal
type Currency = EUR | USD | RUB
type EmailAddress = ...
type CardNumber = ...
type CardType = ...
type CreditCardInfo = ...
type PaymentMethod =
| Cash
| PayPal of EmailAddress
| Card of CreditCardInfo
type PaymentAmount = decimal
type Currency = EUR | USD | RUB
type Payment = {
Amount : PaymentAmount
Currency : Currency
Method : PaymentMethod }
type EmailAddress = ...
type CardNumber = ...
type CardType = ...
type CreditCardInfo = ...
type PaymentMethod =
| Cash
| PayPal of EmailAddress
| Card of CreditCardInfo
type PaymentAmount = decimal
type Currency = EUR | USD | RUB
type Payment = {
Amount : PaymentAmount
Currency : Currency
Method : PaymentMethod }
Composable types can be used as
executable documentation
type Deal = Deck -> (Deck * Card)
type PickupCard = (Hand * Card) -> Hand
type Suit = Club | Diamond | Spade | Heart
type Rank = Two | Three | Four | Five | Six | Seven | Eight
| Nine | Ten | Jack | Queen | King | Ace
type Card = { Suit:Suit; Rank:Rank }
type Hand = Card list
type Deck = Card list
type Player = {Name:string; Hand:Hand}
type Game = { Deck:Deck; Players:Player list }
The domain on one screen!
type CardType = Visa | Mastercard
type CardNumber = string
type EmailAddress = string
type PaymentMethod =
| Cash
| PayPal of EmailAddress
| Card of CreditCardInfo
| Bitcoin of BitcoinAddress
A big topic and not enough time  
More on DDD and designing with types at
fsharpforfunandprofit.com/ddd
Composition in practice:
Time for some real examples!
COMPOSITIONWITH PIPING
(ROMAN NUMERALS)
Technique #1
To Roman Numerals
• Task: How to convert an arabic integer
to roman numerals?
• 5 => "V"
• 12 => "XII"
• 107 => "CVII"
To Roman Numerals
To Roman Numerals
• Use the "tally" approach
– Start with N copies of "I"
– Replace five "I"s with a "V"
– Replace two "V"s with a "X"
– Replace five "X"s with a "L"
– Replace two "L"s with a "C"
– etc
To Roman Numerals
number
etc
Replicate "I"
Replace_IIIII_V
Replace_VV_X
Replace_XXXXX_L
string ToRomanNumerals(int number)
{
// define a helper function for each step
string replace_IIIII_V(string s) =>
s.Replace("IIIII", "V");
string replace_VV_X(string s) =>
s.Replace("VV", "X");
string replace_XXXXX_L(string s) =>
s.Replace("XXXXX", "L");
string replace_LL_C(string s) =>
s.Replace("LL", "C");
// then combine them using piping
return new string('I', number)
.Pipe(replace_IIIII_V)
.Pipe(replace_VV_X)
.Pipe(replace_XXXXX_L)
.Pipe(replace_LL_C);
}
C# example
let toRomanNumerals number =
// define a helper function for each step
let replace_IIIII_V str =
replace "IIIII" "V" str
let replace_VV_X str =
replace "VV" "X" str
let replace_XXXXX_L str =
replace "XXXXX" "L" str
let replace_LL_C str =
replace "LL" "C" str
// then combine them using piping
String.replicate number "I"
|> replace_IIIII_V
|> replace_VV_X
|> replace_XXXXX_L
|> replace_LL_C
F# example
IT'S NOT ALWAYSTHIS
EASY…
function A function BCompose
function A function B
function A and B
Easy!
... But here is a challenge
function AInput Output
function B
Input 1 Output
Input 2
function AInput Output
function B
Input 1 Output
Input 2
Challenge #1: How can
we compose these?

COMPOSITION WITH CURRYING
(ROMAN NUMERALS)
Technique #2
The Replace function
oldValue outputString
newValue
inputString
Replace
Uh-oh! Composition problem
Replace I / V Replace V / X Replace X / L 
Bad news:
Composition patterns
only work for functions that
have one parameter! 
Good news!
Every function can be turned into
a one parameter function 
Haskell Curry
We named this technique after him
Input A
Uncurried
Function
Input B
Output C
Curried
Function
Input A
Intermediate
Function
Output CInput B
What is currying?
after currying
Function as output
Input A
Uncurried
Function
Input B
Output C
Curried
Function
Input A
Intermediate
Function
Output CInput B
What is currying?
One input One input
Currying means that *every* function can be converted
to a series of one input functions
Replace
Before currying
input.Replace(oldValue, newValue);
string output
Replace
Old New
Old
New
After currying
Func<string,string> replace(string oldVal, string newVal) =>
input => input.Replace(oldVal, newVal);
Replace
Old New
Old
New
After currying
Func<string,string> replace(string oldVal, string newVal) =>
input => input.Replace(oldVal, newVal);
Func<string,string> replace(string oldVal, string newVal) =>
input => input.Replace(oldVal, newVal);
Replace
Old New
Old
New
After currying
This lambda (function) is returned
one-parameter
function
string ToRomanNumerals(int number)
{
// define a general helper function
Func<string,string> replace(
string oldValue, string newValue) =>
input => input.Replace(oldValue, newValue);
// then use piping
return new string('I', number)
.Pipe(replace("IIIII","V"))
.Pipe(replace("VV","X"))
.Pipe(replace("XXXXX","L"))
.Pipe(replace("LL","C"));
}
C# example
string ToRomanNumerals(int number)
{
// define a general helper function
Func<string,string> replace(
string oldValue, string newValue) =>
input => input.Replace(oldValue, newValue);
// then use piping
return new string('I', number)
.Pipe(replace("IIIII","V"))
.Pipe(replace("VV","X"))
.Pipe(replace("XXXXX","L"))
.Pipe(replace("LL","C"));
}
C# example
string ToRomanNumerals(int number)
{
// define a general helper function
Func<string,string> replace(
string oldValue, string newValue) =>
input => input.Replace(oldValue, newValue);
// then use piping
return new string('I', number)
.Pipe(replace("IIIII","V"))
.Pipe(replace("VV","X"))
.Pipe(replace("XXXXX","L"))
.Pipe(replace("LL","C"));
}
C# example
Only 2 of the 3
parameters are passed in
The other
parameter comes
from the pipeline
let toRomanNumerals number =
// no helper function needed.
// currying occurs automatically in F#
// combine using piping
String.replicate number "I"
|> replace "IIIII" "V"
|> replace "VV" "X"
|> replace "XXXXX" "L"
|> replace "LL" "C"
F# example
let toRomanNumerals number =
// no helper function needed.
// currying occurs automatically in F#
// combine using piping
String.replicate number "I"
|> replace "IIIII" "V"
|> replace "VV" "X"
|> replace "XXXXX" "L"
|> replace "LL" "C"
Only 2 of the 3
parameters are passed in
F# example
The other
parameter comes
from the pipeline
Partial Application
Partial Application
let add x y = x + y
let multiply x y = x * y
5
|> add 2
|> multiply 3
Piping provides the missing argument
partial application
Partial Application
Replace ReplaceOldNew
Old New
Old
New
String.replicate number "I"
|> replace "IIIII" "V"
|> replace "VV" "X"
|> replace "XXXXX" "L"
|> replace "LL" "C"
Only 2 parameters
passed in
Piping provides the missing argument
Pipelines
are extensible
let toRomanNumerals number =
String.replicate number "I"
|> replace "IIIII" "V"
|> replace "VV" "X"
|> replace "XXXXX" "L"
|> replace "LL" "C"
Composable => extensible
// can easily add new segments to the pipeline
|> replace "VIIII" "IX"
|> replace "IIII" "IV"
|> replace "LXXXX" "XC"
functionInput Output
function
Input 1 Output
Input 2
Challenge #1: How can we compose these?

Here is another challenge
function AInput Output
function BInput
Output 1
Output 2
function AInput Output
function BInput
Output 1
Output 2
Challenge #2: How can we compose these?

COMPOSITIONWITH BIND
(FIZZBUZZ)
Technique #3
FizzBuzz definition
Write a program that takes a number as input
• For multiples of three print "Fizz"
• For multiples of five print "Buzz"
• For multiples of both three and five print "FizzBuzz"
• Otherwise, print the original number
let fizzBuzz n =
if (isDivisibleBy n 15) then
printfn "FizzBuzz"
else if (isDivisibleBy n 3) then
printfn "Fizz"
else if (isDivisibleBy n 5) then
printfn "Buzz"
else
printfn "%i" n
let isDivisibleBy n divisor =
(n % divisor) = 0 // helper function
A simple F# implementation
let fizzBuzz n =
if (isDivisibleBy n 15) then
printfn "FizzBuzz"
else if (isDivisibleBy n 3) then
printfn "Fizz"
else if (isDivisibleBy n 5) then
printfn "Buzz"
else
printfn "%i" n
let isDivisibleBy n divisor =
(n % divisor) = 0 // helper function
A simple F# implementation
Pipeline implementation
number Handle 15 case
Pipeline implementation
Handle 3 case
number Handle 15 case
Pipeline implementation
Handle 3 case
Handle 5 case
number Handle 15 case
Pipeline implementation
Handle 3 case
Handle 5 case
number
Answer
Handle 15 case
Last step
number Handle case
Handled
(e.g. "Fizz", "Buzz")
Unhandled
(e.g. 2, 7, 13)
Unhandled
Handled
Input ->
or
Unhandled
Handled
Input ->
type FizzBuzzResult =
| Unhandled of int // the original int
| Handled of string // "Fizz", Buzz", etc
Idea from http://weblog.raganwald.com/2007/01/dont-overthink-fizzbuzz.html
or
type FizzBuzzResult =
| Unhandled of int // the original int
| Handled of string // "Fizz", Buzz", etc
let handle divisor label n =
if (isDivisibleBy n divisor) then
Handled label
else
Unhandled n
Idea from http://weblog.raganwald.com/2007/01/dont-overthink-fizzbuzz.html
type FizzBuzzResult =
| Unhandled of int // the original int
| Handled of string // "Fizz", Buzz", etc
let handle divisor label n =
if (isDivisibleBy n divisor) then
Handled label
else
Unhandled n
12 |> handle 3 "Fizz" // Handled "Fizz"
10 |> handle 3 "Fizz" // Unhandled 10
10 |> handle 5 "Buzz" // Handled "Buzz"
handle 5 "Buzz"
let fizzbuzz n =
let result15 = n |> handle 15 "FizzBuzz"
match result15 with
| Handled str ->
str
| Unhandled n ->
let result3 = n |> handle 3 "Fizz"
match result3 with
| Handled str ->
str
| Unhandled n ->
let result5 = n |> handle 5 "Buzz"
match result5 with
| Handled str ->
str
| Unhandled n ->
string n // convert to string
First implementation attempt
let fizzbuzz n =
let result15 = n |> handle 15 "FizzBuzz"
match result15 with
| Handled str ->
str
| Unhandled n ->
let result3 = n |> handle 3 "Fizz"
match result3 with
| Handled str ->
str
| Unhandled n ->
let result5 = n |> handle 5 "Buzz"
match result5 with
| Handled str ->
str
| Unhandled n ->
// do something with Unhandled value
let fizzbuzz n =
let result15 = n |> handle 15 "FizzBuzz"
match result15 with
| Handled str ->
str
| Unhandled n ->
let result3 = n |> handle 3 "Fizz"
match result3 with
| Handled str ->
str
| Unhandled n ->
// do something with Unhandled value
// ...
// ...
let fizzbuzz n =
let result15 = n |> handle 15 "FizzBuzz"
match result15 with
| Handled str ->
str
| Unhandled n ->
// do something with Unhandled value
// ...
// ...
if Handled then
// return the string
if Unhandled then
// do something with the number
If Unhandled
If Handled
Bypass and
return the string
let ifUnhandledDo f result =
match result with
| Handled str ->
Handled str
| Unhandled n ->
f n
let fizzbuzz n =
n
|> handle 15 "FizzBuzz"
|> ifUnhandledDo (handle 3 "Fizz")
|> ifUnhandledDo (handle 5 "Buzz")
|> lastStep
let fizzbuzz n =
n
|> handle 15 "FizzBuzz"
|> ifUnhandledDo (handle 3 "Fizz")
|> ifUnhandledDo (handle 5 "Buzz")
|> lastStep
let fizzbuzz n =
n
|> handle 15 "FizzBuzz"
|> ifUnhandledDo (handle 3 "Fizz")
|> ifUnhandledDo (handle 5 "Buzz")
|> lastStep
let fizzbuzz n =
n
|> handle 15 "FizzBuzz"
|> ifUnhandledDo (handle 3 "Fizz")
|> ifUnhandledDo (handle 5 "Buzz")
|> lastStep
let fizzbuzz n =
n
|> handle 15 "FizzBuzz"
|> ifUnhandledDo (handle 3 "Fizz")
|> ifUnhandledDo (handle 5 "Buzz")
|> lastStep
let lastStep result =
match result with
| Handled str ->
str
| Unhandled n ->
string(n) // convert to string
let fizzbuzz n =
n
|> handle 15 "FizzBuzz"
|> ifUnhandledDo (handle 3 "Fizz")
|> ifUnhandledDo (handle 5 "Buzz")
|> lastStep
Composable => easy to extend
let fizzbuzz n =
n
|> handle 15 "FizzBuzz"
|> ifUnhandledDo (handle 3 "Fizz")
|> ifUnhandledDo (handle 5 "Buzz")
|> ifUnhandledDo (handle 7 "Baz")
|> lastStep
Composable => easy to extend
let fizzbuzz n =
n
|> handle 15 "FizzBuzz"
|> ifUnhandledDo (handle 3 "Fizz")
|> ifUnhandledDo (handle 5 "Buzz")
|> ifUnhandledDo (handle 7 "Baz")
|> ifUnhandledDo (handle 11 "Pozz")
|> lastStep
Composable => easy to extend
let fizzbuzz n =
n
|> handle 15 "FizzBuzz"
|> ifUnhandledDo (handle 3 "Fizz")
|> ifUnhandledDo (handle 5 "Buzz")
|> ifUnhandledDo (handle 7 "Baz")
|> ifUnhandledDo (handle 11 "Pozz")
|> ifUnhandledDo (handle 13 "Tazz")
|> lastStep
Composable => easy to extend
Another example:
Chaining tasks
When task
completesWait Wait
a.k.a "promise", "future"
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 ->
etc
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 ->
do something
let taskExample input =
let taskX = startTask input
taskX.WhenFinished (fun x ->
let taskY = startAnotherTask x
taskY.WhenFinished (fun y ->
do something
let taskExample input =
let taskX = startTask input
taskX.WhenFinished (fun x ->
do something
let whenFinishedDo f task =
task.WhenFinished (fun taskResult ->
f taskResult)
let taskExample input =
startTask input
|> whenFinishedDo startAnotherTask
|> whenFinishedDo startThirdTask
|> whenFinishedDo ...
Parameterize the next step
MONADS!
Is there a general solution to
handling functions like this?
Yes! “Bind” is the answer!
Bind all the things!
How do we compose these?
>> >>
Composing one-track functions is fine...
>> >>
... and composing two-track functions is fine...
 
... but composing points/switches is not allowed!
Two-track input Two-track output
One-track input Two-track output


Two-track input Two-track output
Two-track input Two-track output
A function transformer
let bind nextFunction result =
match result with
| Unhandled n ->
nextFunction n
| Handled str ->
Handled str
Two-track input Two-track output
let bind nextFunction result =
match result with
| Unhandled n ->
nextFunction n
| Handled str ->
Handled str
Two-track input Two-track output
let bind nextFunction result =
match result with
| Unhandled n ->
nextFunction n
| Handled str ->
Handled str
Two-track input Two-track output
let bind nextFunction result =
match result with
| Unhandled n ->
nextFunction n
| Handled str ->
Handled str
Two-track input Two-track output
let bind nextFunction result =
match result with
| Unhandled n ->
nextFunction n
| Handled str ->
Handled str
Two-track input Two-track output
FP terminology
• A monad is
– A data type
– With an associated "bind" function
– (and some other stuff)
• A monadic function is
– A switch/points function
– "bind" is used to compose them
type FizzBuzzResult =
| Unhandled of int
| Handled of string
function AInput Output
function BInput
Output 1
Output 2
Challenge #2: How can we compose these?

KLEISLI COMPOSITION
(WEB SERVICE)
Technique #4
compose
with
Kleisli Composition
Kleisli Composition
Kleisli Composition
Kleisli Composition
=
compose
with
The result is the
same kind of thing
Kleisli Composition
The "Lego" approach to
building a web server
Async<HttpContext option>HttpContext
A HttpHandler "WebPart"
Async<HttpContext option>HttpContext
A HttpHandler "WebPart"
=>=>
The result is another
HttpHandler so you can
keep adding and adding
Composition of HttpHandlers
Kleisli composition symbol
path "/hello"
Checks request path
(might fail)
matches path
doesn't match
OK "Hello"
Sets response
200 OK
path "/hello" >=> OK "Hello"
Checks request path
(might fail)
Sets response
>=>
A new WebPart
choose [
]
Picks first HttpHandler
that succeeds
choose [
path "/hello" >=> OK "Hello"
path "/goodbye" >=> OK "Goodbye"
]
Pick first path
that succeeds
GET
Only succeeds if
request is a GET
GET >=> choose [
path "/hello" >=> OK "Hello"
path "/goodbye" >=> OK "Goodbye"
]
let app = choose [
]
startWebServer defaultConfig app
A complete web app
GET >=> choose [
path "/hello" >=> OK "Hello"
path "/goodbye" >=> OK "Goodbye"
]
POST >=> choose [
path "/hello" >=> OK "Hello POST"
path "/goodbye" >=> OK "Goodbye POST"
]
Http
Response
Http
Request
No classes, no inheritance, one-directional data flow!
Review
• The philosophy of composition
– Connectable,reusable parts
– Building bigger things from smaller things
• FP principles:
– Composable functions
– Composable types
Review
A taste of various composition techniques:
– Piping with "|>"
– Currying/partial application
– Composition using "bind" (monads!)
– Kleisli composition using ">=>"
Don't worry about understanding it all,
but hopefully it's not so scary now!
Why bother?
Benefits of composition:
• Reusable parts – no strings attached
• Testable – parts can be tested in isolation
• Understandable – data flows in one direction
• Maintainable – all dependencies are explicit
• Extendable – can add new parts without touching
old code
• A different way of thinking – it's good for
your brain to learn new things!
Slides and video here
fsharpforfunandprofit.com/composition
Thank you!
@ScottWlaschin Me on twitter
My book

More Related Content

What's hot

Railway Oriented Programming
Railway Oriented ProgrammingRailway Oriented Programming
Railway Oriented ProgrammingScott Wlaschin
 
Domain Driven Design with the F# type System -- F#unctional Londoners 2014
Domain Driven Design with the F# type System -- F#unctional Londoners 2014Domain Driven Design with the F# type System -- F#unctional Londoners 2014
Domain Driven Design with the F# type System -- F#unctional Londoners 2014Scott Wlaschin
 
Functional Programming Patterns (NDC London 2014)
Functional Programming Patterns (NDC London 2014)Functional Programming Patterns (NDC London 2014)
Functional Programming Patterns (NDC London 2014)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
 
The Functional Programming Toolkit (NDC Oslo 2019)
The Functional Programming Toolkit (NDC Oslo 2019)The Functional Programming Toolkit (NDC Oslo 2019)
The Functional Programming Toolkit (NDC Oslo 2019)Scott Wlaschin
 
Designing with Capabilities
Designing with CapabilitiesDesigning with Capabilities
Designing with CapabilitiesScott Wlaschin
 
An introduction to property based testing
An introduction to property based testingAn introduction to property based testing
An introduction to property based testingScott Wlaschin
 
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
 
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
 
The Power Of Composition (DotNext 2019)
The Power Of Composition (DotNext 2019)The Power Of Composition (DotNext 2019)
The Power Of Composition (DotNext 2019)Scott Wlaschin
 
The Power of Composition
The Power of CompositionThe Power of Composition
The Power of CompositionScott Wlaschin
 
If You Think You Can Stay Away from Functional Programming, You Are Wrong
If You Think You Can Stay Away from Functional Programming, You Are WrongIf You Think You Can Stay Away from Functional Programming, You Are Wrong
If You Think You Can Stay Away from Functional Programming, You Are WrongMario Fusco
 
Laziness, trampolines, monoids and other functional amenities: this is not yo...
Laziness, trampolines, monoids and other functional amenities: this is not yo...Laziness, trampolines, monoids and other functional amenities: this is not yo...
Laziness, trampolines, monoids and other functional amenities: this is not yo...Mario Fusco
 
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
 
Clean Pragmatic Architecture - Avoiding a Monolith
Clean Pragmatic Architecture - Avoiding a MonolithClean Pragmatic Architecture - Avoiding a Monolith
Clean Pragmatic Architecture - Avoiding a MonolithVictor Rentea
 
Clean code and Code Smells
Clean code and Code SmellsClean code and Code Smells
Clean code and Code SmellsMario Sangiorgio
 

What's hot (20)

Railway Oriented Programming
Railway Oriented ProgrammingRailway Oriented Programming
Railway Oriented Programming
 
Domain Driven Design with the F# type System -- F#unctional Londoners 2014
Domain Driven Design with the F# type System -- F#unctional Londoners 2014Domain Driven Design with the F# type System -- F#unctional Londoners 2014
Domain Driven Design with the F# type System -- F#unctional Londoners 2014
 
Functional Programming Patterns (NDC London 2014)
Functional Programming Patterns (NDC London 2014)Functional Programming Patterns (NDC London 2014)
Functional Programming Patterns (NDC London 2014)
 
Domain Modeling Made Functional (KanDDDinsky 2019)
Domain Modeling Made Functional (KanDDDinsky 2019)Domain Modeling Made Functional (KanDDDinsky 2019)
Domain Modeling Made Functional (KanDDDinsky 2019)
 
The Functional Programming Toolkit (NDC Oslo 2019)
The Functional Programming Toolkit (NDC Oslo 2019)The Functional Programming Toolkit (NDC Oslo 2019)
The Functional Programming Toolkit (NDC Oslo 2019)
 
Designing with Capabilities
Designing with CapabilitiesDesigning with Capabilities
Designing with Capabilities
 
An introduction to property based testing
An introduction to property based testingAn introduction to property based testing
An introduction to property based testing
 
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...
 
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...
 
Clean code slide
Clean code slideClean code slide
Clean code slide
 
The Power Of Composition (DotNext 2019)
The Power Of Composition (DotNext 2019)The Power Of Composition (DotNext 2019)
The Power Of Composition (DotNext 2019)
 
Clean coding-practices
Clean coding-practicesClean coding-practices
Clean coding-practices
 
The Theory of Chains
The Theory of ChainsThe Theory of Chains
The Theory of Chains
 
The Power of Composition
The Power of CompositionThe Power of Composition
The Power of Composition
 
If You Think You Can Stay Away from Functional Programming, You Are Wrong
If You Think You Can Stay Away from Functional Programming, You Are WrongIf You Think You Can Stay Away from Functional Programming, You Are Wrong
If You Think You Can Stay Away from Functional Programming, You Are Wrong
 
Laziness, trampolines, monoids and other functional amenities: this is not yo...
Laziness, trampolines, monoids and other functional amenities: this is not yo...Laziness, trampolines, monoids and other functional amenities: this is not yo...
Laziness, trampolines, monoids and other functional amenities: this is not yo...
 
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)
 
Clean Pragmatic Architecture - Avoiding a Monolith
Clean Pragmatic Architecture - Avoiding a MonolithClean Pragmatic Architecture - Avoiding a Monolith
Clean Pragmatic Architecture - Avoiding a Monolith
 
Clean code
Clean codeClean code
Clean code
 
Clean code and Code Smells
Clean code and Code SmellsClean code and Code Smells
Clean code and Code Smells
 

Similar to The Power of Composition (NDC Oslo 2020)

DISE - Windows Based Application Development in C#
DISE - Windows Based Application Development in C#DISE - Windows Based Application Development in C#
DISE - Windows Based Application Development in C#Rasan Samarasinghe
 
DITEC - Programming with C#.NET
DITEC - Programming with C#.NETDITEC - Programming with C#.NET
DITEC - Programming with C#.NETRasan Samarasinghe
 
Think sharp, write swift
Think sharp, write swiftThink sharp, write swift
Think sharp, write swiftPascal Batty
 
F# and Reactive Programming for iOS
F# and Reactive Programming for iOSF# and Reactive Programming for iOS
F# and Reactive Programming for iOSBrad Pillow
 
Type Driven Development with TypeScript
Type Driven Development with TypeScriptType Driven Development with TypeScript
Type Driven Development with TypeScriptGarth Gilmour
 
Functional pogramming hl overview
Functional pogramming hl overviewFunctional pogramming hl overview
Functional pogramming hl overviewElad Avneri
 
Hadoop Streaming Tutorial With Python
Hadoop Streaming Tutorial With PythonHadoop Streaming Tutorial With Python
Hadoop Streaming Tutorial With PythonJoe Stein
 
Programming with python
Programming with pythonProgramming with python
Programming with pythonsarogarage
 
Introduction to C++
Introduction to C++ Introduction to C++
Introduction to C++ Bharat Kalia
 
Five Languages in a Moment
Five Languages in a MomentFive Languages in a Moment
Five Languages in a MomentSergio Gil
 
Compiler2016 by abcdabcd987
Compiler2016 by abcdabcd987Compiler2016 by abcdabcd987
Compiler2016 by abcdabcd987乐群 陈
 
Extreme Swift
Extreme SwiftExtreme Swift
Extreme SwiftMovel
 
Антон Молдован "Type driven development with f#"
Антон Молдован "Type driven development with f#"Антон Молдован "Type driven development with f#"
Антон Молдован "Type driven development with f#"Fwdays
 
Brixton Library Technology Initiative Week1 Recap
Brixton Library Technology Initiative Week1 RecapBrixton Library Technology Initiative Week1 Recap
Brixton Library Technology Initiative Week1 RecapBasil Bibi
 
The top 5 JavaScript issues in all our codebases
The top 5 JavaScript issues in all our codebasesThe top 5 JavaScript issues in all our codebases
The top 5 JavaScript issues in all our codebasesPhil Nash
 
name name2 n
name name2 nname name2 n
name name2 ncallroom
 

Similar to The Power of Composition (NDC Oslo 2020) (20)

Python slide
Python slidePython slide
Python slide
 
DISE - Windows Based Application Development in C#
DISE - Windows Based Application Development in C#DISE - Windows Based Application Development in C#
DISE - Windows Based Application Development in C#
 
Cucumber
CucumberCucumber
Cucumber
 
DITEC - Programming with C#.NET
DITEC - Programming with C#.NETDITEC - Programming with C#.NET
DITEC - Programming with C#.NET
 
Think sharp, write swift
Think sharp, write swiftThink sharp, write swift
Think sharp, write swift
 
F# and Reactive Programming for iOS
F# and Reactive Programming for iOSF# and Reactive Programming for iOS
F# and Reactive Programming for iOS
 
Type Driven Development with TypeScript
Type Driven Development with TypeScriptType Driven Development with TypeScript
Type Driven Development with TypeScript
 
Functional pogramming hl overview
Functional pogramming hl overviewFunctional pogramming hl overview
Functional pogramming hl overview
 
Hadoop Streaming Tutorial With Python
Hadoop Streaming Tutorial With PythonHadoop Streaming Tutorial With Python
Hadoop Streaming Tutorial With Python
 
Programming with python
Programming with pythonProgramming with python
Programming with python
 
Introduction to C++
Introduction to C++ Introduction to C++
Introduction to C++
 
Five Languages in a Moment
Five Languages in a MomentFive Languages in a Moment
Five Languages in a Moment
 
Compiler2016 by abcdabcd987
Compiler2016 by abcdabcd987Compiler2016 by abcdabcd987
Compiler2016 by abcdabcd987
 
Extreme Swift
Extreme SwiftExtreme Swift
Extreme Swift
 
Антон Молдован "Type driven development with f#"
Антон Молдован "Type driven development with f#"Антон Молдован "Type driven development with f#"
Антон Молдован "Type driven development with f#"
 
Brixton Library Technology Initiative Week1 Recap
Brixton Library Technology Initiative Week1 RecapBrixton Library Technology Initiative Week1 Recap
Brixton Library Technology Initiative Week1 Recap
 
The top 5 JavaScript issues in all our codebases
The top 5 JavaScript issues in all our codebasesThe top 5 JavaScript issues in all our codebases
The top 5 JavaScript issues in all our codebases
 
ppt7
ppt7ppt7
ppt7
 
ppt2
ppt2ppt2
ppt2
 
name name2 n
name name2 nname name2 n
name name2 n
 

More from 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
 
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
 
Dr Frankenfunctor and the Monadster
Dr Frankenfunctor and the MonadsterDr Frankenfunctor and the Monadster
Dr Frankenfunctor and the MonadsterScott Wlaschin
 
Enterprise Tic-Tac-Toe
Enterprise Tic-Tac-ToeEnterprise Tic-Tac-Toe
Enterprise Tic-Tac-ToeScott Wlaschin
 

More from Scott Wlaschin (9)

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
 
F# for C# Programmers
F# for C# ProgrammersF# for C# Programmers
F# for C# Programmers
 
Designing with capabilities (DDD-EU 2017)
Designing with capabilities (DDD-EU 2017)Designing with capabilities (DDD-EU 2017)
Designing with capabilities (DDD-EU 2017)
 
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
 
Dr Frankenfunctor and the Monadster
Dr Frankenfunctor and the MonadsterDr Frankenfunctor and the Monadster
Dr Frankenfunctor and the Monadster
 
Enterprise Tic-Tac-Toe
Enterprise Tic-Tac-ToeEnterprise Tic-Tac-Toe
Enterprise Tic-Tac-Toe
 
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
 

Recently uploaded

VictoriaMetrics Q1 Meet Up '24 - Community & News Update
VictoriaMetrics Q1 Meet Up '24 - Community & News UpdateVictoriaMetrics Q1 Meet Up '24 - Community & News Update
VictoriaMetrics Q1 Meet Up '24 - Community & News UpdateVictoriaMetrics
 
Strategies for using alternative queries to mitigate zero results
Strategies for using alternative queries to mitigate zero resultsStrategies for using alternative queries to mitigate zero results
Strategies for using alternative queries to mitigate zero resultsJean Silva
 
Leveraging AI for Mobile App Testing on Real Devices | Applitools + Kobiton
Leveraging AI for Mobile App Testing on Real Devices | Applitools + KobitonLeveraging AI for Mobile App Testing on Real Devices | Applitools + Kobiton
Leveraging AI for Mobile App Testing on Real Devices | Applitools + KobitonApplitools
 
OpenChain AI Study Group - Europe and Asia Recap - 2024-04-11 - Full Recording
OpenChain AI Study Group - Europe and Asia Recap - 2024-04-11 - Full RecordingOpenChain AI Study Group - Europe and Asia Recap - 2024-04-11 - Full Recording
OpenChain AI Study Group - Europe and Asia Recap - 2024-04-11 - Full RecordingShane Coughlan
 
Machine Learning Software Engineering Patterns and Their Engineering
Machine Learning Software Engineering Patterns and Their EngineeringMachine Learning Software Engineering Patterns and Their Engineering
Machine Learning Software Engineering Patterns and Their EngineeringHironori Washizaki
 
GraphSummit Madrid - Product Vision and Roadmap - Luis Salvador Neo4j
GraphSummit Madrid - Product Vision and Roadmap - Luis Salvador Neo4jGraphSummit Madrid - Product Vision and Roadmap - Luis Salvador Neo4j
GraphSummit Madrid - Product Vision and Roadmap - Luis Salvador Neo4jNeo4j
 
Comparing Linux OS Image Update Models - EOSS 2024.pdf
Comparing Linux OS Image Update Models - EOSS 2024.pdfComparing Linux OS Image Update Models - EOSS 2024.pdf
Comparing Linux OS Image Update Models - EOSS 2024.pdfDrew Moseley
 
Precise and Complete Requirements? An Elusive Goal
Precise and Complete Requirements? An Elusive GoalPrecise and Complete Requirements? An Elusive Goal
Precise and Complete Requirements? An Elusive GoalLionel Briand
 
Real-time Tracking and Monitoring with Cargo Cloud Solutions.pptx
Real-time Tracking and Monitoring with Cargo Cloud Solutions.pptxReal-time Tracking and Monitoring with Cargo Cloud Solutions.pptx
Real-time Tracking and Monitoring with Cargo Cloud Solutions.pptxRTS corp
 
Ronisha Informatics Private Limited Catalogue
Ronisha Informatics Private Limited CatalogueRonisha Informatics Private Limited Catalogue
Ronisha Informatics Private Limited Catalogueitservices996
 
OpenChain Education Work Group Monthly Meeting - 2024-04-10 - Full Recording
OpenChain Education Work Group Monthly Meeting - 2024-04-10 - Full RecordingOpenChain Education Work Group Monthly Meeting - 2024-04-10 - Full Recording
OpenChain Education Work Group Monthly Meeting - 2024-04-10 - Full RecordingShane Coughlan
 
Simplifying Microservices & Apps - The art of effortless development - Meetup...
Simplifying Microservices & Apps - The art of effortless development - Meetup...Simplifying Microservices & Apps - The art of effortless development - Meetup...
Simplifying Microservices & Apps - The art of effortless development - Meetup...Rob Geurden
 
2024-04-09 - From Complexity to Clarity - AWS Summit AMS.pdf
2024-04-09 - From Complexity to Clarity - AWS Summit AMS.pdf2024-04-09 - From Complexity to Clarity - AWS Summit AMS.pdf
2024-04-09 - From Complexity to Clarity - AWS Summit AMS.pdfAndrey Devyatkin
 
Powering Real-Time Decisions with Continuous Data Streams
Powering Real-Time Decisions with Continuous Data StreamsPowering Real-Time Decisions with Continuous Data Streams
Powering Real-Time Decisions with Continuous Data StreamsSafe Software
 
What’s New in VictoriaMetrics: Q1 2024 Updates
What’s New in VictoriaMetrics: Q1 2024 UpdatesWhat’s New in VictoriaMetrics: Q1 2024 Updates
What’s New in VictoriaMetrics: Q1 2024 UpdatesVictoriaMetrics
 
Salesforce Implementation Services PPT By ABSYZ
Salesforce Implementation Services PPT By ABSYZSalesforce Implementation Services PPT By ABSYZ
Salesforce Implementation Services PPT By ABSYZABSYZ Inc
 
Large Language Models for Test Case Evolution and Repair
Large Language Models for Test Case Evolution and RepairLarge Language Models for Test Case Evolution and Repair
Large Language Models for Test Case Evolution and RepairLionel Briand
 
eSoftTools IMAP Backup Software and migration tools
eSoftTools IMAP Backup Software and migration toolseSoftTools IMAP Backup Software and migration tools
eSoftTools IMAP Backup Software and migration toolsosttopstonverter
 
Post Quantum Cryptography – The Impact on Identity
Post Quantum Cryptography – The Impact on IdentityPost Quantum Cryptography – The Impact on Identity
Post Quantum Cryptography – The Impact on Identityteam-WIBU
 
The Role of IoT and Sensor Technology in Cargo Cloud Solutions.pptx
The Role of IoT and Sensor Technology in Cargo Cloud Solutions.pptxThe Role of IoT and Sensor Technology in Cargo Cloud Solutions.pptx
The Role of IoT and Sensor Technology in Cargo Cloud Solutions.pptxRTS corp
 

Recently uploaded (20)

VictoriaMetrics Q1 Meet Up '24 - Community & News Update
VictoriaMetrics Q1 Meet Up '24 - Community & News UpdateVictoriaMetrics Q1 Meet Up '24 - Community & News Update
VictoriaMetrics Q1 Meet Up '24 - Community & News Update
 
Strategies for using alternative queries to mitigate zero results
Strategies for using alternative queries to mitigate zero resultsStrategies for using alternative queries to mitigate zero results
Strategies for using alternative queries to mitigate zero results
 
Leveraging AI for Mobile App Testing on Real Devices | Applitools + Kobiton
Leveraging AI for Mobile App Testing on Real Devices | Applitools + KobitonLeveraging AI for Mobile App Testing on Real Devices | Applitools + Kobiton
Leveraging AI for Mobile App Testing on Real Devices | Applitools + Kobiton
 
OpenChain AI Study Group - Europe and Asia Recap - 2024-04-11 - Full Recording
OpenChain AI Study Group - Europe and Asia Recap - 2024-04-11 - Full RecordingOpenChain AI Study Group - Europe and Asia Recap - 2024-04-11 - Full Recording
OpenChain AI Study Group - Europe and Asia Recap - 2024-04-11 - Full Recording
 
Machine Learning Software Engineering Patterns and Their Engineering
Machine Learning Software Engineering Patterns and Their EngineeringMachine Learning Software Engineering Patterns and Their Engineering
Machine Learning Software Engineering Patterns and Their Engineering
 
GraphSummit Madrid - Product Vision and Roadmap - Luis Salvador Neo4j
GraphSummit Madrid - Product Vision and Roadmap - Luis Salvador Neo4jGraphSummit Madrid - Product Vision and Roadmap - Luis Salvador Neo4j
GraphSummit Madrid - Product Vision and Roadmap - Luis Salvador Neo4j
 
Comparing Linux OS Image Update Models - EOSS 2024.pdf
Comparing Linux OS Image Update Models - EOSS 2024.pdfComparing Linux OS Image Update Models - EOSS 2024.pdf
Comparing Linux OS Image Update Models - EOSS 2024.pdf
 
Precise and Complete Requirements? An Elusive Goal
Precise and Complete Requirements? An Elusive GoalPrecise and Complete Requirements? An Elusive Goal
Precise and Complete Requirements? An Elusive Goal
 
Real-time Tracking and Monitoring with Cargo Cloud Solutions.pptx
Real-time Tracking and Monitoring with Cargo Cloud Solutions.pptxReal-time Tracking and Monitoring with Cargo Cloud Solutions.pptx
Real-time Tracking and Monitoring with Cargo Cloud Solutions.pptx
 
Ronisha Informatics Private Limited Catalogue
Ronisha Informatics Private Limited CatalogueRonisha Informatics Private Limited Catalogue
Ronisha Informatics Private Limited Catalogue
 
OpenChain Education Work Group Monthly Meeting - 2024-04-10 - Full Recording
OpenChain Education Work Group Monthly Meeting - 2024-04-10 - Full RecordingOpenChain Education Work Group Monthly Meeting - 2024-04-10 - Full Recording
OpenChain Education Work Group Monthly Meeting - 2024-04-10 - Full Recording
 
Simplifying Microservices & Apps - The art of effortless development - Meetup...
Simplifying Microservices & Apps - The art of effortless development - Meetup...Simplifying Microservices & Apps - The art of effortless development - Meetup...
Simplifying Microservices & Apps - The art of effortless development - Meetup...
 
2024-04-09 - From Complexity to Clarity - AWS Summit AMS.pdf
2024-04-09 - From Complexity to Clarity - AWS Summit AMS.pdf2024-04-09 - From Complexity to Clarity - AWS Summit AMS.pdf
2024-04-09 - From Complexity to Clarity - AWS Summit AMS.pdf
 
Powering Real-Time Decisions with Continuous Data Streams
Powering Real-Time Decisions with Continuous Data StreamsPowering Real-Time Decisions with Continuous Data Streams
Powering Real-Time Decisions with Continuous Data Streams
 
What’s New in VictoriaMetrics: Q1 2024 Updates
What’s New in VictoriaMetrics: Q1 2024 UpdatesWhat’s New in VictoriaMetrics: Q1 2024 Updates
What’s New in VictoriaMetrics: Q1 2024 Updates
 
Salesforce Implementation Services PPT By ABSYZ
Salesforce Implementation Services PPT By ABSYZSalesforce Implementation Services PPT By ABSYZ
Salesforce Implementation Services PPT By ABSYZ
 
Large Language Models for Test Case Evolution and Repair
Large Language Models for Test Case Evolution and RepairLarge Language Models for Test Case Evolution and Repair
Large Language Models for Test Case Evolution and Repair
 
eSoftTools IMAP Backup Software and migration tools
eSoftTools IMAP Backup Software and migration toolseSoftTools IMAP Backup Software and migration tools
eSoftTools IMAP Backup Software and migration tools
 
Post Quantum Cryptography – The Impact on Identity
Post Quantum Cryptography – The Impact on IdentityPost Quantum Cryptography – The Impact on Identity
Post Quantum Cryptography – The Impact on Identity
 
The Role of IoT and Sensor Technology in Cargo Cloud Solutions.pptx
The Role of IoT and Sensor Technology in Cargo Cloud Solutions.pptxThe Role of IoT and Sensor Technology in Cargo Cloud Solutions.pptx
The Role of IoT and Sensor Technology in Cargo Cloud Solutions.pptx
 

The Power of Composition (NDC Oslo 2020)

  • 1. The Power Of Composition NDC Oslo 2020 @ScottWlaschin fsharpforfunandprofit.com
  • 2. The Power Of Composition 1. The philosophy of composition 2. Ideas of functional programming – Functions and how to compose them – Types and how to compose them 3. Composition in practice – Roman Numerals – FizzBuzz gone functional – Uh oh, monads! – A web service
  • 4. Prerequisites for understanding composition • You must have been a child at some point • You must have played with Lego • You must have played with toy trains
  • 6. Lego Philosophy 1. All pieces are designed to be connected 2. The pieces are reusable in many contexts 3. Connect two pieces together and get another "piece" that can still be connected
  • 7. All pieces are designed to be connected
  • 8. The pieces are reusable in different contexts
  • 9. Connect two pieces together and get another "piece" that can still be connected
  • 10. Make big things from small things in the same way
  • 11.
  • 12. Wooden Railway Track Philosophy 1. All pieces are designed to be connected 2. The pieces are reusable in many contexts 3. Connect two pieces together and get another "piece" that can still be connected
  • 13. All pieces are designed to be connected
  • 14. The pieces are reusable in different contexts
  • 15. Connect two pieces together and get another "piece" that can still be connected You can keep adding and adding.
  • 16. Make big things from small things in the same way
  • 17. If you understand Lego and wooden railways, then you know everything about composition!
  • 18. THE IDEAS OF FUNCTIONAL PROGRAMMING
  • 19. Four ideas behind FP Function 3.Types are not classes 1. Functions are things 2. Build bigger functions using composition 4. Build bigger types using composition
  • 20. FP idea #1: Functions are things Function
  • 21. The Tunnel of Transformation Function apple -> banana A function is a thing which transforms inputs to outputs
  • 22. A function is a standalone thing, not attached to a class
  • 23. A function is a standalone thing, not attached to a class It can be used for inputs and outputs of other functions
  • 24. A function can be an output thing input
  • 25. output A function can be an input thing
  • 26. input output A function can be a parameter
  • 28. FP idea #2: Build bigger functions using composition
  • 29. Function 1 apple -> banana Function 2 banana -> cherry
  • 30. >> Function 1 apple -> banana Function 2 banana -> cherry
  • 31. New Function apple -> cherry Can't tell it was built from smaller functions! Where did the banana go?
  • 32. Function composition in F# and C# using the "piping" approach
  • 33. int add1(int x) => x + 1; int times2(int x) => x * 2; int square(int x) => x * x; add1(5); // = 6 times2(add1(5)); // = 12 square(times2(add1(5))); // = 144 Nested function calls can be confusing if too deep
  • 34. add15 6 times2 12 square 144
  • 35. 5 |> add1 // = 6 5 |> add1 |> times2 // = 12 5 |> add1 |> times2 |> square // = 144 add1 times2 square5 6 12 144 F# example
  • 36. add1 times2 square5 6 12 144 5.Pipe(add1); 5.Pipe(add1).Pipe(times2); 5.Pipe(add1).Pipe(times2).Pipe(square); C# example
  • 37. Building big things from functions It's compositions all the way up
  • 39. 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
  • 42. Http Response Http Request Even for complex applications, data flows only in one direction
  • 43.
  • 44.
  • 45. FP idea #3: Types are not classes
  • 46. So, what is a type then? A type is a just a name for a set of things Set of valid inputs Set of valid outputs Function
  • 47. Set of valid inputs Set of valid outputs Function 1 2 3 4 5 6 This is type "integer" A type is a just a name for a set of things
  • 48. Set of valid inputs Set of valid outputs Function This is type "string" "abc" "but" "cobol" "double" "end" "float" A type is a just a name for a set of things
  • 49. Set of valid inputs Set of valid outputs Function This is type "Person" Donna Roy Javier Mendoza Nathan Logan Shawna Ingram Abel Ortiz Lena Robbins GordonWood A type is a just a name for a set of things
  • 50. Set of valid inputs Set of valid outputs Function This is type "Fruit" A type is a just a name for a set of things
  • 51. Set of valid inputs Set of valid outputs Function This is a type of Fruit->Fruit functions A type is a just a name for a set of things
  • 52. FP idea #4: Types can be composed too
  • 54. Bigger types are built from smaller types by: Composing with “AND” Composing with “OR”
  • 56. Compose with “AND” enum AppleVariety { Red, Green } enum BananaVariety { Yellow, Brown } enum CherryVariety { Tart, Sweet } struct FruitSalad { AppleVariety Apple; BananaVariety Banana; CherryVariety Cherry; } C# example Apple AND Banana AND Cherry
  • 57. Compose with “AND” type AppleVariety = Red | Green type BananaVariety = Yellow | Brown type CherryVariety = Tart | Sweet type FruitSalad = { Apple: AppleVariety Banana: BananaVariety Cherry: CherryVariety } F# example
  • 58. Snack = OR OR Compose with “OR” type Snack = | Apple of AppleVariety | Banana of BananaVariety | Cherry of CherryVariety
  • 59. A real world example of composing types
  • 60. Some requirements: We accept three forms of payment: Cash, Paypal, or CreditCard. For Cash we don't need any extra information For Paypal we need an email address For Cards we need a card type and card number
  • 61. interface IPaymentMethod {..} class Cash() : IPaymentMethod {..} class Paypal(string emailAddress): IPaymentMethod {..} class Card(string cardType, string cardNo) : IPaymentMethod {..} In OO design you would probably implement it as an interface and a set of subclasses, like this:
  • 62. type EmailAddress = string type CardNumber = string In F# you would probably implement by composing types, like this:
  • 63. type EmailAddress = ... type CardNumber = … type CardType = Visa | Mastercard type CreditCardInfo = { CardType : CardType CardNumber : CardNumber }
  • 64. type EmailAddress = ... type CardNumber = ... type CardType = ... type CreditCardInfo = ... type PaymentMethod = | Cash | PayPal of EmailAddress | Card of CreditCardInfo
  • 65. type EmailAddress = ... type CardNumber = ... type CardType = ... type CreditCardInfo = ... type PaymentMethod = | Cash | PayPal of EmailAddress | Card of CreditCardInfo type PaymentAmount = decimal type Currency = EUR | USD | RUB
  • 66. type EmailAddress = ... type CardNumber = ... type CardType = ... type CreditCardInfo = ... type PaymentMethod = | Cash | PayPal of EmailAddress | Card of CreditCardInfo type PaymentAmount = decimal type Currency = EUR | USD | RUB type Payment = { Amount : PaymentAmount Currency : Currency Method : PaymentMethod }
  • 67. type EmailAddress = ... type CardNumber = ... type CardType = ... type CreditCardInfo = ... type PaymentMethod = | Cash | PayPal of EmailAddress | Card of CreditCardInfo type PaymentAmount = decimal type Currency = EUR | USD | RUB type Payment = { Amount : PaymentAmount Currency : Currency Method : PaymentMethod }
  • 68.
  • 69. Composable types can be used as executable documentation
  • 70. type Deal = Deck -> (Deck * Card) type PickupCard = (Hand * Card) -> Hand type Suit = Club | Diamond | Spade | Heart type Rank = Two | Three | Four | Five | Six | Seven | Eight | Nine | Ten | Jack | Queen | King | Ace type Card = { Suit:Suit; Rank:Rank } type Hand = Card list type Deck = Card list type Player = {Name:string; Hand:Hand} type Game = { Deck:Deck; Players:Player list } The domain on one screen!
  • 71. type CardType = Visa | Mastercard type CardNumber = string type EmailAddress = string type PaymentMethod = | Cash | PayPal of EmailAddress | Card of CreditCardInfo | Bitcoin of BitcoinAddress
  • 72. A big topic and not enough time   More on DDD and designing with types at fsharpforfunandprofit.com/ddd
  • 73. Composition in practice: Time for some real examples!
  • 75. To Roman Numerals • Task: How to convert an arabic integer to roman numerals? • 5 => "V" • 12 => "XII" • 107 => "CVII"
  • 77. To Roman Numerals • Use the "tally" approach – Start with N copies of "I" – Replace five "I"s with a "V" – Replace two "V"s with a "X" – Replace five "X"s with a "L" – Replace two "L"s with a "C" – etc
  • 78. To Roman Numerals number etc Replicate "I" Replace_IIIII_V Replace_VV_X Replace_XXXXX_L
  • 79. string ToRomanNumerals(int number) { // define a helper function for each step string replace_IIIII_V(string s) => s.Replace("IIIII", "V"); string replace_VV_X(string s) => s.Replace("VV", "X"); string replace_XXXXX_L(string s) => s.Replace("XXXXX", "L"); string replace_LL_C(string s) => s.Replace("LL", "C"); // then combine them using piping return new string('I', number) .Pipe(replace_IIIII_V) .Pipe(replace_VV_X) .Pipe(replace_XXXXX_L) .Pipe(replace_LL_C); } C# example
  • 80. let toRomanNumerals number = // define a helper function for each step let replace_IIIII_V str = replace "IIIII" "V" str let replace_VV_X str = replace "VV" "X" str let replace_XXXXX_L str = replace "XXXXX" "L" str let replace_LL_C str = replace "LL" "C" str // then combine them using piping String.replicate number "I" |> replace_IIIII_V |> replace_VV_X |> replace_XXXXX_L |> replace_LL_C F# example
  • 84. function A and B Easy!
  • 85. ... But here is a challenge
  • 86. function AInput Output function B Input 1 Output Input 2
  • 87. function AInput Output function B Input 1 Output Input 2 Challenge #1: How can we compose these? 
  • 88. COMPOSITION WITH CURRYING (ROMAN NUMERALS) Technique #2
  • 89. The Replace function oldValue outputString newValue inputString Replace
  • 90. Uh-oh! Composition problem Replace I / V Replace V / X Replace X / L 
  • 91. Bad news: Composition patterns only work for functions that have one parameter! 
  • 92. Good news! Every function can be turned into a one parameter function 
  • 93. Haskell Curry We named this technique after him
  • 94. Input A Uncurried Function Input B Output C Curried Function Input A Intermediate Function Output CInput B What is currying? after currying Function as output
  • 95. Input A Uncurried Function Input B Output C Curried Function Input A Intermediate Function Output CInput B What is currying? One input One input Currying means that *every* function can be converted to a series of one input functions
  • 97. Replace Old New Old New After currying Func<string,string> replace(string oldVal, string newVal) => input => input.Replace(oldVal, newVal);
  • 98. Replace Old New Old New After currying Func<string,string> replace(string oldVal, string newVal) => input => input.Replace(oldVal, newVal);
  • 99. Func<string,string> replace(string oldVal, string newVal) => input => input.Replace(oldVal, newVal); Replace Old New Old New After currying This lambda (function) is returned one-parameter function
  • 100. string ToRomanNumerals(int number) { // define a general helper function Func<string,string> replace( string oldValue, string newValue) => input => input.Replace(oldValue, newValue); // then use piping return new string('I', number) .Pipe(replace("IIIII","V")) .Pipe(replace("VV","X")) .Pipe(replace("XXXXX","L")) .Pipe(replace("LL","C")); } C# example
  • 101. string ToRomanNumerals(int number) { // define a general helper function Func<string,string> replace( string oldValue, string newValue) => input => input.Replace(oldValue, newValue); // then use piping return new string('I', number) .Pipe(replace("IIIII","V")) .Pipe(replace("VV","X")) .Pipe(replace("XXXXX","L")) .Pipe(replace("LL","C")); } C# example
  • 102. string ToRomanNumerals(int number) { // define a general helper function Func<string,string> replace( string oldValue, string newValue) => input => input.Replace(oldValue, newValue); // then use piping return new string('I', number) .Pipe(replace("IIIII","V")) .Pipe(replace("VV","X")) .Pipe(replace("XXXXX","L")) .Pipe(replace("LL","C")); } C# example Only 2 of the 3 parameters are passed in The other parameter comes from the pipeline
  • 103. let toRomanNumerals number = // no helper function needed. // currying occurs automatically in F# // combine using piping String.replicate number "I" |> replace "IIIII" "V" |> replace "VV" "X" |> replace "XXXXX" "L" |> replace "LL" "C" F# example
  • 104. let toRomanNumerals number = // no helper function needed. // currying occurs automatically in F# // combine using piping String.replicate number "I" |> replace "IIIII" "V" |> replace "VV" "X" |> replace "XXXXX" "L" |> replace "LL" "C" Only 2 of the 3 parameters are passed in F# example The other parameter comes from the pipeline
  • 106. Partial Application let add x y = x + y let multiply x y = x * y 5 |> add 2 |> multiply 3 Piping provides the missing argument partial application
  • 107. Partial Application Replace ReplaceOldNew Old New Old New String.replicate number "I" |> replace "IIIII" "V" |> replace "VV" "X" |> replace "XXXXX" "L" |> replace "LL" "C" Only 2 parameters passed in Piping provides the missing argument
  • 109. let toRomanNumerals number = String.replicate number "I" |> replace "IIIII" "V" |> replace "VV" "X" |> replace "XXXXX" "L" |> replace "LL" "C" Composable => extensible // can easily add new segments to the pipeline |> replace "VIIII" "IX" |> replace "IIII" "IV" |> replace "LXXXX" "XC"
  • 110. functionInput Output function Input 1 Output Input 2 Challenge #1: How can we compose these? 
  • 111. Here is another challenge
  • 112. function AInput Output function BInput Output 1 Output 2
  • 113. function AInput Output function BInput Output 1 Output 2 Challenge #2: How can we compose these? 
  • 115. FizzBuzz definition Write a program that takes a number as input • For multiples of three print "Fizz" • For multiples of five print "Buzz" • For multiples of both three and five print "FizzBuzz" • Otherwise, print the original number
  • 116. let fizzBuzz n = if (isDivisibleBy n 15) then printfn "FizzBuzz" else if (isDivisibleBy n 3) then printfn "Fizz" else if (isDivisibleBy n 5) then printfn "Buzz" else printfn "%i" n let isDivisibleBy n divisor = (n % divisor) = 0 // helper function A simple F# implementation
  • 117. let fizzBuzz n = if (isDivisibleBy n 15) then printfn "FizzBuzz" else if (isDivisibleBy n 3) then printfn "Fizz" else if (isDivisibleBy n 5) then printfn "Buzz" else printfn "%i" n let isDivisibleBy n divisor = (n % divisor) = 0 // helper function A simple F# implementation
  • 119. Pipeline implementation Handle 3 case number Handle 15 case
  • 120. Pipeline implementation Handle 3 case Handle 5 case number Handle 15 case
  • 121. Pipeline implementation Handle 3 case Handle 5 case number Answer Handle 15 case Last step
  • 122. number Handle case Handled (e.g. "Fizz", "Buzz") Unhandled (e.g. 2, 7, 13)
  • 124. Unhandled Handled Input -> type FizzBuzzResult = | Unhandled of int // the original int | Handled of string // "Fizz", Buzz", etc Idea from http://weblog.raganwald.com/2007/01/dont-overthink-fizzbuzz.html or
  • 125. type FizzBuzzResult = | Unhandled of int // the original int | Handled of string // "Fizz", Buzz", etc let handle divisor label n = if (isDivisibleBy n divisor) then Handled label else Unhandled n Idea from http://weblog.raganwald.com/2007/01/dont-overthink-fizzbuzz.html
  • 126. type FizzBuzzResult = | Unhandled of int // the original int | Handled of string // "Fizz", Buzz", etc let handle divisor label n = if (isDivisibleBy n divisor) then Handled label else Unhandled n
  • 127. 12 |> handle 3 "Fizz" // Handled "Fizz" 10 |> handle 3 "Fizz" // Unhandled 10 10 |> handle 5 "Buzz" // Handled "Buzz" handle 5 "Buzz"
  • 128. let fizzbuzz n = let result15 = n |> handle 15 "FizzBuzz" match result15 with | Handled str -> str | Unhandled n -> let result3 = n |> handle 3 "Fizz" match result3 with | Handled str -> str | Unhandled n -> let result5 = n |> handle 5 "Buzz" match result5 with | Handled str -> str | Unhandled n -> string n // convert to string First implementation attempt
  • 129. let fizzbuzz n = let result15 = n |> handle 15 "FizzBuzz" match result15 with | Handled str -> str | Unhandled n -> let result3 = n |> handle 3 "Fizz" match result3 with | Handled str -> str | Unhandled n -> let result5 = n |> handle 5 "Buzz" match result5 with | Handled str -> str | Unhandled n -> // do something with Unhandled value
  • 130. let fizzbuzz n = let result15 = n |> handle 15 "FizzBuzz" match result15 with | Handled str -> str | Unhandled n -> let result3 = n |> handle 3 "Fizz" match result3 with | Handled str -> str | Unhandled n -> // do something with Unhandled value // ... // ...
  • 131. let fizzbuzz n = let result15 = n |> handle 15 "FizzBuzz" match result15 with | Handled str -> str | Unhandled n -> // do something with Unhandled value // ... // ...
  • 132. if Handled then // return the string if Unhandled then // do something with the number
  • 133. If Unhandled If Handled Bypass and return the string
  • 134. let ifUnhandledDo f result = match result with | Handled str -> Handled str | Unhandled n -> f n
  • 135. let fizzbuzz n = n |> handle 15 "FizzBuzz" |> ifUnhandledDo (handle 3 "Fizz") |> ifUnhandledDo (handle 5 "Buzz") |> lastStep
  • 136. let fizzbuzz n = n |> handle 15 "FizzBuzz" |> ifUnhandledDo (handle 3 "Fizz") |> ifUnhandledDo (handle 5 "Buzz") |> lastStep
  • 137. let fizzbuzz n = n |> handle 15 "FizzBuzz" |> ifUnhandledDo (handle 3 "Fizz") |> ifUnhandledDo (handle 5 "Buzz") |> lastStep
  • 138. let fizzbuzz n = n |> handle 15 "FizzBuzz" |> ifUnhandledDo (handle 3 "Fizz") |> ifUnhandledDo (handle 5 "Buzz") |> lastStep
  • 139. let fizzbuzz n = n |> handle 15 "FizzBuzz" |> ifUnhandledDo (handle 3 "Fizz") |> ifUnhandledDo (handle 5 "Buzz") |> lastStep let lastStep result = match result with | Handled str -> str | Unhandled n -> string(n) // convert to string
  • 140. let fizzbuzz n = n |> handle 15 "FizzBuzz" |> ifUnhandledDo (handle 3 "Fizz") |> ifUnhandledDo (handle 5 "Buzz") |> lastStep Composable => easy to extend
  • 141. let fizzbuzz n = n |> handle 15 "FizzBuzz" |> ifUnhandledDo (handle 3 "Fizz") |> ifUnhandledDo (handle 5 "Buzz") |> ifUnhandledDo (handle 7 "Baz") |> lastStep Composable => easy to extend
  • 142. let fizzbuzz n = n |> handle 15 "FizzBuzz" |> ifUnhandledDo (handle 3 "Fizz") |> ifUnhandledDo (handle 5 "Buzz") |> ifUnhandledDo (handle 7 "Baz") |> ifUnhandledDo (handle 11 "Pozz") |> lastStep Composable => easy to extend
  • 143. let fizzbuzz n = n |> handle 15 "FizzBuzz" |> ifUnhandledDo (handle 3 "Fizz") |> ifUnhandledDo (handle 5 "Buzz") |> ifUnhandledDo (handle 7 "Baz") |> ifUnhandledDo (handle 11 "Pozz") |> ifUnhandledDo (handle 13 "Tazz") |> lastStep Composable => easy to extend
  • 145. When task completesWait Wait a.k.a "promise", "future"
  • 146. 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 -> etc
  • 147. 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 -> do something
  • 148. let taskExample input = let taskX = startTask input taskX.WhenFinished (fun x -> let taskY = startAnotherTask x taskY.WhenFinished (fun y -> do something
  • 149. let taskExample input = let taskX = startTask input taskX.WhenFinished (fun x -> do something
  • 150. let whenFinishedDo f task = task.WhenFinished (fun taskResult -> f taskResult) let taskExample input = startTask input |> whenFinishedDo startAnotherTask |> whenFinishedDo startThirdTask |> whenFinishedDo ... Parameterize the next step
  • 152. Is there a general solution to handling functions like this?
  • 153. Yes! “Bind” is the answer! Bind all the things!
  • 154. How do we compose these?
  • 155.
  • 156. >> >> Composing one-track functions is fine...
  • 157. >> >> ... and composing two-track functions is fine...
  • 158.   ... but composing points/switches is not allowed!
  • 159. Two-track input Two-track output One-track input Two-track output  
  • 161. Two-track input Two-track output A function transformer
  • 162. let bind nextFunction result = match result with | Unhandled n -> nextFunction n | Handled str -> Handled str Two-track input Two-track output
  • 163. let bind nextFunction result = match result with | Unhandled n -> nextFunction n | Handled str -> Handled str Two-track input Two-track output
  • 164. let bind nextFunction result = match result with | Unhandled n -> nextFunction n | Handled str -> Handled str Two-track input Two-track output
  • 165. let bind nextFunction result = match result with | Unhandled n -> nextFunction n | Handled str -> Handled str Two-track input Two-track output
  • 166. let bind nextFunction result = match result with | Unhandled n -> nextFunction n | Handled str -> Handled str Two-track input Two-track output
  • 167. FP terminology • A monad is – A data type – With an associated "bind" function – (and some other stuff) • A monadic function is – A switch/points function – "bind" is used to compose them type FizzBuzzResult = | Unhandled of int | Handled of string
  • 168. function AInput Output function BInput Output 1 Output 2 Challenge #2: How can we compose these? 
  • 174. = compose with The result is the same kind of thing Kleisli Composition
  • 175. The "Lego" approach to building a web server
  • 178. =>=> The result is another HttpHandler so you can keep adding and adding Composition of HttpHandlers Kleisli composition symbol
  • 179. path "/hello" Checks request path (might fail) matches path doesn't match
  • 181. path "/hello" >=> OK "Hello" Checks request path (might fail) Sets response >=> A new WebPart
  • 182. choose [ ] Picks first HttpHandler that succeeds
  • 183. choose [ path "/hello" >=> OK "Hello" path "/goodbye" >=> OK "Goodbye" ] Pick first path that succeeds
  • 185. GET >=> choose [ path "/hello" >=> OK "Hello" path "/goodbye" >=> OK "Goodbye" ]
  • 186. let app = choose [ ] startWebServer defaultConfig app A complete web app GET >=> choose [ path "/hello" >=> OK "Hello" path "/goodbye" >=> OK "Goodbye" ] POST >=> choose [ path "/hello" >=> OK "Hello POST" path "/goodbye" >=> OK "Goodbye POST" ]
  • 187. Http Response Http Request No classes, no inheritance, one-directional data flow!
  • 188. Review • The philosophy of composition – Connectable,reusable parts – Building bigger things from smaller things • FP principles: – Composable functions – Composable types
  • 189. Review A taste of various composition techniques: – Piping with "|>" – Currying/partial application – Composition using "bind" (monads!) – Kleisli composition using ">=>" Don't worry about understanding it all, but hopefully it's not so scary now!
  • 190. Why bother? Benefits of composition: • Reusable parts – no strings attached • Testable – parts can be tested in isolation • Understandable – data flows in one direction • Maintainable – all dependencies are explicit • Extendable – can add new parts without touching old code • A different way of thinking – it's good for your brain to learn new things!
  • 191. Slides and video here fsharpforfunandprofit.com/composition Thank you! @ScottWlaschin Me on twitter My book