SlideShare una empresa de Scribd logo
1 de 165
Descargar para leer sin conexión
The Power Of Composition
@ScottWlaschin
fsharpforfunandprofit.com
^ for beginners in FP
The Power Of Composition
• The philosophy of composition
• Functional programming principles
– Functions and how to compose them
– Types and how to compose them
• Composition in practice
– Two simple examples
– FizzBuzz gone carbonated
– A web service
PREREQUISITES
How to learn functional programming
• Have a "beginner's mind"
• Forget everything you know about object-
oriented programming
– No loops!
– No variables!
– No objects!
The "Are you ready to learn FP?" test
• What is a class?
• What is a method?
• What is a for-loop?
• What is inheritance?
You *must* pass
this test before
continuing!
Answers!
• What is a class?
– Correct answer: "I don't know"
• What is a method?
– Correct answer: "No idea"
• What is a for-loop?
– Correct answer: "I couldn't tell you"
• What is inheritance?
– Correct answer: "Search me"
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. Connect two pieces together and get
another "piece" that can still be connected
3. The pieces are reusable in many contexts
All pieces are designed to be connected
Connect two pieces together and
get another "piece" that can still be connected
The pieces are reusable in different contexts
Make big things from small things in the same way
Wooden RailwayTrack Philosophy
1. All pieces are designed to be connected
2. Connect two pieces together and get
another "piece" that can still be connected
3. The pieces are reusable in many contexts
All pieces are designed to be connected
Connect two pieces together and get
another "piece" that can still be connected
You can keep adding and adding.
The pieces are reusable in different contexts
Make big things from small things in the same way
Unix Philosophy
• Write programs that do one thing well.
– To do a new job, build afresh rather than complicate
old programs by adding new "features".
• Write programs to work together.
– Expect the output of every program to become the
input to another, as yet unknown, program.
• Write programs to handle text streams, because
that is a universal interface.
All pieces are designed to be connected
The pieces are reusable
You don't need to create a special adapter to make connections.
THE PRINCIPLES OF
FUNCTIONAL PROGRAMMING
Core principles of FP
Function
Types are not classes
Functions are things
Composition everywhere
Core FP principle:
Functions are things
Function
Functions as things
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
It can be used for inputs and outputs
of other functions
input
A function can be an output
A function is a standalone thing
output
A function can be an input
A function is a standalone thing
input output
A function can be a parameter
A function is a standalone thing
Core FP 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!
Where did the banana go?
(abstraction)
Function composition
New Function
apple -> cherry
A Very Important Point: For composition to work properly:
• Data must be immutable
• Functions must be self-contained, with no strings attached:
no side-effects, no I/O, no globals, etc
let add1 x = x + 1
let double x = x + x
let add1_double = add1 >> double
let x = add1_double 5 // 12
Composition
DoubleAdd1
let add1_double_square =
add1 >> double >> square
let x = add1_double_square 5 // 144
Composition
DoubleAdd1 Square
Piping
add1 5 // = 6
double (add1 5) // = 12
square (double (add1 5)) // = 144
5 |> add1 // = 6
5 |> add1 |> double // = 12
5 |> add1 |> double |> square // = 144
add1 double square5 6 12 144
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
• "monoids"
– for combining strings, lists, etc.
• "monads"
– for composing functions with effects
• CategoryTheory
– or, "Composition Theory"
More kinds of composition
for functional programmers…
Core FP principle:
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
Composition everywhere:
Types can be composed too
Algebraic type system
New types are built from smaller types by:
Composing with “AND”
Composing with “OR”
Example: pairs, tuples, records
FruitSalad = One each of and and
Compose with “AND”
type FruitSalad = {
Apple: AppleVariety
Banana: BananaVariety
Cherry: CherryVariety
}
Snack = or or
Compose with “OR”
type Snack =
| Apple of AppleVariety
| Banana of BananaVariety
| Cherry of CherryVariety
Real world example
of type composition
Example of some requirements:
We accept three forms of payment:
Cash, Check, or Card.
For Cash we don't need any extra information
For Checks we need a check number
For Cards we need a card type and card number
interface IPaymentMethod
{..}
class Cash() : IPaymentMethod
{..}
class Check(int checkNo): 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 CheckNumber = int
type CardNumber = string
In F# you would probably implement by composing
types, like this:
type CheckNumber = ...
type CardNumber = …
type CardType = Visa | Mastercard
type CreditCardInfo = {
CardType : CardType
CardNumber : CardNumber
}
type CheckNumber = ...
type CardNumber = ...
type CardType = ...
type CreditCardInfo = ...
type PaymentMethod =
| Cash
| Check of CheckNumber
| Card of CreditCardInfo
type CheckNumber = ...
type CardNumber = ...
type CardType = ...
type CreditCardInfo = ...
type PaymentMethod =
| Cash
| Check of CheckNumber
| Card of CreditCardInfo
type PaymentAmount = decimal
type Currency = EUR | USD
type CheckNumber = ...
type CardNumber = ...
type CardType = ...
type CreditCardInfo = ...
type PaymentMethod =
| Cash
| Check of CheckNumber
| Card of CreditCardInfo
type PaymentAmount = decimal
type Currency = EUR | USD
type Payment = {
Amount : PaymentAmount
Currency: Currency
Method: PaymentMethod }
FP design principle:
Types are executable documentation
type Deal = Deck –› (Deck * Card)
type PickupCard = (Hand * Card) –› Hand
Types are executable documentation
type Suit = Club | Diamond | Spade | Heart
type Rank = Two | Three | Four | Five | Six | Seven | Eight
| Nine |Ten | Jack | Queen | King | Ace
type Card = Suit * 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!
Types are executable documentation
type CardType =Visa | Mastercard
type CardNumber = CardNumber of string
type CheckNumber = CheckNumber of int
type PaymentMethod =
| Cash
| Check of CheckNumber
| Card of CardType * CardNumber
A big topic and not enough time  
More on DDD and designing with types at
fsharpforfunandprofit.com/ddd
BASIC COMPOSITION:
THINK OF A NUMBER
Think of a number
• Think of a number.
• Add one to it.
• Square it.
• Subtract one.
• Divide by the number you first thought of.
• Subtract the number you first thought of.
• The answer is TWO!
Think of a number
AddOne
SquareItSubtractOne
DivideByTheNumberYouThoughtOf
SubtractTheNumberYouThoughtOf
TheNumberYouThoughtOf
Answer
let thinkOfANumber numberYouThoughtOf =
// define a function for each step
let addOne x = x + 1
let squareIt x = x * x
let subtractOne x = x - 1
let divideByTheNumberYouThoughtOf x = x / numberYouThoughtOf
let subtractTheNumberYouThoughtOf x = x - numberYouThoughtOf
// then combine them using piping
numberYouThoughtOf
|> addOne
|> squareIt
|> subtractOne
|> divideByTheNumberYouThoughtOf
|> subtractTheNumberYouThoughtOf
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 BInput
Output 1
Output 2
function C
Input 1 Output
Input 2
function AInput Output
function BInput
Output 1
Output 2
Challenge: How can
we compose these?
function AInput Output
function C
Input 1 Output
Input 2
Challenge: How can
we compose these?
COMPOSING MULTIPLE INPUTS:
ROMAN NUMERALS
To Roman Numerals
• Task: convert an integer to Roman Numerals
• V = 5, X = 10, C = 100 etc
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"
– Replace five "C"s with a "D"
– Replace two "D"s with a "M"
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
Currying means that *every* function can be converted
to a series of one input functions
Replace
Before currying
let replace oldValue newValue inputStr =
inputStr.Replace(oldValue,newValue)
Replace
Old New
Old
New
After currying
let replace oldValue newValue =
fun inputStr ->
inputStr.Replace(oldValue,newValue)
Partial Application
Replace ReplaceOldNew
Old New
Old
New
let replace_IIIII_V = replace "IIIII" "V"
// replace_IIIII_V is a function
let replace_VV_X = replace "VV" "X"
// replace_VV_X is a function
Only 2 parameters
passed in
To Roman Numerals
integer
etc
Replicate "I"
Replace_IIIII_V
Replace_VV_X
Replace_XXXXX_L
let toRomanNumerals number =
let replace_IIIII_V = replace "IIIII" "V"
let replace_VV_X = replace "VV" "X"
let replace_XXXXX_L = replace "XXXXX" "L"
let replace_LL_C = replace "LL" "C"
let replace_CCCCC_D = replace "CCCCC" "D"
let replace_DD_M = replace "DD" "M"
String.replicate number "I"
|> replace_IIIII_V
|> replace_VV_X
|> replace_XXXXX_L
|> replace_LL_C
|> replace_CCCCC_D
|> replace_DD_M
Inline Partial Application
let add x y = x + y
let multiply x y = x * y
5
|> add 2
|> multiply 2
Piping
"inline" partial application
Inline Partial Application
let add x y = x + y
let multiply x y = x * y
[1..10]
|> List.map (add 2)
|> List.map (multiply 2)
Two "inline" partial applications
let toRomanNumerals number =
String.replicate number "I"
|> replace "IIIII" "V"
|> replace "VV" "X"
|> replace "XXXXX" "L"
|> replace "LL" "C"
|> replace "CCCCC" "D"
|> replace "DD" "M"
With inline partial application
let toRomanNumerals number =
String.replicate number "I"
|> replace "IIIII" "V"
|> replace "VV" "X"
|> replace "XXXXX" "L"
|> replace "LL" "C"
|> replace "CCCCC" "D"
|> replace "DD" "M"
With inline partial application
// 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: How can
we compose these?
COMPOSING MULTIPLE OUTPUTS:
FIZZBUZZ
FizzBuzz definition
• Write a program that prints the numbers
from 1 to 100
• But:
– For multiples of three print "Fizz" instead
– For multiples of five print "Buzz" instead
– For multiples of both three and five print
"FizzBuzz" instead.
let fizzBuzz max =
for n in [1..max] do
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
A simple implementation
Pipeline implementation
Handle 3 case
Handle 5 case
number
Answer
Handle 15 case
Handle remaining
number Handle case
Carbonated
(e.g. "Fizz", "Buzz")
Uncarbonated
(e.g. 2, 7, 13)
Uncarbonated
Carbonated
Input ->
type CarbonationResult =
| Uncarbonated of int // unprocessed
| Carbonated of string // "Fizz", Buzz", etc
FizzBuzz core
let carbonate divisor label n =
if (isDivisibleBy n divisor) then
Carbonated label
else
Uncarbonated n
Idea from http://weblog.raganwald.com/2007/01/dont-overthink-fizzbuzz.html
12 |> carbonate 3 "Fizz" // Carbonated "Fizz"
10 |> carbonate 3 "Fizz" // Uncarbonated 10
10 |> carbonate 5 "Buzz" // Carbonated "Buzz"
If Uncarbonated
If Carbonated
bypass
How to we compose them?
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!
let fizzbuzz n =
let result15 = n |> carbonate 15 "FizzBuzz"
match result15 with
| Carbonated str ->
str
| Uncarbonated n ->
let result3 = n |> carbonate 3 "Fizz"
match result3 with
| Carbonated str ->
str
| Uncarbonated n ->
let result5 = n |> carbonate 5 "Buzz"
match result5 with
| Carbonated str ->
str
| Uncarbonated n ->
string n // convert to string
First implementation attempt
let fizzbuzz n =
let result15 = n |> carbonate 15 "FizzBuzz"
match result15 with
| Carbonated str ->
str
| Uncarbonated n ->
let result3 = n |> carbonate 3 "Fizz"
match result3 with
| Carbonated str ->
str
| Uncarbonated n ->
let result5 = n |> carbonate 5 "Buzz"
match result5 with
| Carbonated str ->
str
| Uncarbonated n ->
// do something with Uncarbonated value
let fizzbuzz n =
let result15 = n |> carbonate 15 "FizzBuzz"
match result15 with
| Carbonated str ->
str
| Uncarbonated n ->
let result3 = n |> carbonate 3 "Fizz"
match result3 with
| Carbonated str ->
str
| Uncarbonated n ->
// do something with Uncarbonated value
let fizzbuzz n =
let result15 = n |> carbonate 15 "FizzBuzz"
match result15 with
| Carbonated str ->
str
| Uncarbonated n ->
// do something with Uncarbonated value
if Carbonated
// return the string
if Uncarbonated then
// do something with the number
let ifUncarbonatedDo f result =
match result with
| Carbonated str ->
Carbonated str
| Uncarbonated n ->
f n
let fizzbuzz n =
n
|> carbonate 15 "FizzBuzz"
|> ifUncarbonatedDo (carbonate 3 "Fizz")
|> ifUncarbonatedDo (carbonate 5 "Buzz")
|> carbonateRemaining
let carbonateRemaining result =
match result with
| Carbonated str ->
str
| Uncarbonated n ->
string(n)
MAKING LOOPS
COMPOSABLE
Another composition problem
List of
numbers
FizzBizz for one number

Solution: the "map" transformer
List input List outputFizzBizz for lists
FizzBizz for one number
List.map
// final version of FizzBuzz
let fizzbuzz100 =
[1..100]
|> List.map fizzBuzz
|> List.iter (printfn "%s") // I/O only at end
let fizzbuzz n =
n
|> carbonate 15 "FizzBuzz"
|> ifUncarbonatedDo (carbonate 3 "Fizz")
|> ifUncarbonatedDo (carbonate 5 "Buzz")
|> carbonateRemaining
THE M-WORD
Is there a general solution to
handling functions like this?
Yes! “Bind” is the answer!
Bind all the things!
Two-track input Two-track output
One-track input Two-track output


Two-track input Two-track output
Two-track input Two-track output
let bind nextFunction result =
match result with
| Uncarbonated n ->
nextFunction n
| Carbonated str ->
Carbonated str
Two-track input Two-track output
let bind nextFunction result =
match result with
| Uncarbonated n ->
nextFunction n
| Carbonated str ->
Carbonated str
Two-track input Two-track output
let bind nextFunction result =
match result with
| Uncarbonated n ->
nextFunction n
| Carbonated str ->
Carbonated str
Two-track input Two-track output
let bind nextFunction result =
match result with
| Uncarbonated n ->
nextFunction n
| Carbonated str ->
Carbonated 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
Example:
Using bind to chain 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 bind f task =
task.WhenFinished (fun taskResult ->
f taskResult)
let taskExample input =
startTask input
|> bind startAnotherTask
|> bind startThirdTask
|> bind ...
Rewritten using bind:
let ( >>= ) x f = x |> bind
let taskExample input =
startTask input
>>= startAnotherTask
>>= startThirdTask
>>= ...
Rewritten using >>=
A common symbol for "bind"
Example:
Composing error-generating functions
Example of scenario with errors
Name is blank
Email not valid
Validate request
Canonicalize email
Fetch existing user record
Update existing user record
User not found
Db error
Authorization error
Timeout
Validate
Generates a possible error
Validate Canonicalize
Generates a possible error Always succeeds
Validate Canonicalize DbFetch
Generates a possible error Generates a possible errorAlways succeeds
Validate Canonicalize DbFetch DbUpdate
Generates a possible error Generates a possible errorAlways succeeds Doesn't return
How can we glue these
mismatched functions together?
map
Converting everything to two-track
bind
map
Converting everything to two-track
bind
map
tee map
Converting everything to two-track
Validate Canonicalize DbFetch DbUpdate
Now we *can* compose
them easily!
map bind tee, then map
KLEISLI COMPOSITION:
WEB SERVICE
=+
Result is
same kind of thing
Kleisli Composition
Async<HttpContext option>HttpContext
A "WebPart" (suave.io library)
See suave.io site for more
=>=>
Result is another
WebPart so you can repeat
WebPart Composition
Kleisli composition symbol
path "/hello" >=> OK "Hello" // a WebPart
Checks request path
(might fail)
Sets response
choose [
path "/hello" >=> OK "Hello"
path "/goodbye" >=> OK "Goodbye"
]
Picks first WebPart
that succeeds
GET >=> choose [
path "/hello" >=> OK "Hello"
path "/goodbye" >=> OK "Goodbye"
]
Only succeeds if
request is a GET
let app = choose [
GET >=> choose [
path "/hello" >=> OK "Hello"
path "/goodbye" >=> OK "Goodbye"
]
POST >=> choose [
path "/hello" >=> OK "Hello POST"
path "/goodbye" >=> OK "Goodbye POST"
]
]
startWebServer defaultConfig app
A complete web app
Http
Response
Http
Request
As I promised – no classes, no loops, etc!
Review
• The philosophy of composition
– Connectable, no adapters, reusable parts
• FP principles:
– Composable functions
– Composable types
• Basic composition
– Composition with ">>"
– Piping with "|>"
• Using partial application to help composition
• Monads and monadic functions
– Composition using "bind" / ">>="
– Kleisli composition using ">=>"
Slides and video here
fsharpforfunandprofit.com/composition
Thank you!
"Domain modelling Made Functional" book
fsharpforfunandprofit.com/books
@ScottWlaschin Me on twitter
fsharpforfunandprofit.com/videos

Más contenido relacionado

La actualidad más candente

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
 

La actualidad más candente (20)

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)
 
Domain Modeling Made Functional (KanDDDinsky 2019)
Domain Modeling Made Functional (KanDDDinsky 2019)Domain Modeling Made Functional (KanDDDinsky 2019)
Domain Modeling Made Functional (KanDDDinsky 2019)
 
Enterprise Tic-Tac-Toe
Enterprise Tic-Tac-ToeEnterprise Tic-Tac-Toe
Enterprise Tic-Tac-Toe
 
Clean Pragmatic Architecture - Avoiding a Monolith
Clean Pragmatic Architecture - Avoiding a MonolithClean Pragmatic Architecture - Avoiding a Monolith
Clean Pragmatic Architecture - Avoiding a Monolith
 
Clean coding-practices
Clean coding-practicesClean coding-practices
Clean coding-practices
 
Clean code
Clean codeClean code
Clean code
 
Map(), flatmap() and reduce() are your new best friends: simpler collections,...
Map(), flatmap() and reduce() are your new best friends: simpler collections,...Map(), flatmap() and reduce() are your new best friends: simpler collections,...
Map(), flatmap() and reduce() are your new best friends: simpler collections,...
 
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...
 
Functional Programming Patterns (BuildStuff '14)
Functional Programming Patterns (BuildStuff '14)Functional Programming Patterns (BuildStuff '14)
Functional Programming Patterns (BuildStuff '14)
 
F# for C# Programmers
F# for C# ProgrammersF# for C# Programmers
F# for C# Programmers
 
Idiomatic Kotlin
Idiomatic KotlinIdiomatic Kotlin
Idiomatic Kotlin
 
Clean code slide
Clean code slideClean code slide
Clean code slide
 
Railway Oriented Programming
Railway Oriented ProgrammingRailway Oriented Programming
Railway Oriented Programming
 
Clean code and Code Smells
Clean code and Code SmellsClean code and Code Smells
Clean code and Code Smells
 
clean code book summary - uncle bob - English version
clean code book summary - uncle bob - English versionclean code book summary - uncle bob - English version
clean code book summary - uncle bob - English version
 
Clean pragmatic architecture @ devflix
Clean pragmatic architecture @ devflixClean pragmatic architecture @ devflix
Clean pragmatic architecture @ devflix
 
Functional Patterns with Java8 @Bucharest Java User Group
Functional Patterns with Java8 @Bucharest Java User GroupFunctional Patterns with Java8 @Bucharest Java User Group
Functional Patterns with Java8 @Bucharest Java User Group
 
Clean Code
Clean CodeClean Code
Clean Code
 
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 code
Clean codeClean code
Clean code
 

Similar a The Power of Composition

Functional pogramming hl overview
Functional pogramming hl overviewFunctional pogramming hl overview
Functional pogramming hl overview
Elad Avneri
 
How I Learned to Stop Worrying and Love Legacy Code - Ox:Agile 2018
How I Learned to Stop Worrying and Love Legacy Code - Ox:Agile 2018How I Learned to Stop Worrying and Love Legacy Code - Ox:Agile 2018
How I Learned to Stop Worrying and Love Legacy Code - Ox:Agile 2018
Mike Harris
 
LINQ Inside
LINQ InsideLINQ Inside
LINQ Inside
jeffz
 
Get a Little Help with Your Help Desk Application
Get a Little Help with Your Help Desk ApplicationGet a Little Help with Your Help Desk Application
Get a Little Help with Your Help Desk Application
Iron Speed
 

Similar a The Power of Composition (20)

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)
 
Rubyconf2016 - Solving communication problems in distributed teams with BDD
Rubyconf2016 - Solving communication problems in distributed teams with BDDRubyconf2016 - Solving communication problems in distributed teams with BDD
Rubyconf2016 - Solving communication problems in distributed teams with BDD
 
Programming Fundamentals
Programming FundamentalsProgramming Fundamentals
Programming Fundamentals
 
ProgFund_Lecture_4_Functions_and_Modules-1.pdf
ProgFund_Lecture_4_Functions_and_Modules-1.pdfProgFund_Lecture_4_Functions_and_Modules-1.pdf
ProgFund_Lecture_4_Functions_and_Modules-1.pdf
 
Refactoring
RefactoringRefactoring
Refactoring
 
Compiler2016 by abcdabcd987
Compiler2016 by abcdabcd987Compiler2016 by abcdabcd987
Compiler2016 by abcdabcd987
 
Taming the Legacy Beast: Turning wild old code into a sleak new thoroughbread.
Taming the Legacy Beast: Turning wild old code into a sleak new thoroughbread.Taming the Legacy Beast: Turning wild old code into a sleak new thoroughbread.
Taming the Legacy Beast: Turning wild old code into a sleak new thoroughbread.
 
Functional pogramming hl overview
Functional pogramming hl overviewFunctional pogramming hl overview
Functional pogramming hl overview
 
Functional Programming - Worth the Effort
Functional Programming - Worth the EffortFunctional Programming - Worth the Effort
Functional Programming - Worth the Effort
 
resolvendo problemas de comunicação em equipes distribuídas com bdd
resolvendo problemas de comunicação em equipes distribuídas com bddresolvendo problemas de comunicação em equipes distribuídas com bdd
resolvendo problemas de comunicação em equipes distribuídas com bdd
 
How I Learned to Stop Worrying and Love Legacy Code - Ox:Agile 2018
How I Learned to Stop Worrying and Love Legacy Code - Ox:Agile 2018How I Learned to Stop Worrying and Love Legacy Code - Ox:Agile 2018
How I Learned to Stop Worrying and Love Legacy Code - Ox:Agile 2018
 
CiviCRM API v3
CiviCRM API v3CiviCRM API v3
CiviCRM API v3
 
Data Workflows for Machine Learning - Seattle DAML
Data Workflows for Machine Learning - Seattle DAMLData Workflows for Machine Learning - Seattle DAML
Data Workflows for Machine Learning - Seattle DAML
 
Data Workflows for Machine Learning - SF Bay Area ML
Data Workflows for Machine Learning - SF Bay Area MLData Workflows for Machine Learning - SF Bay Area ML
Data Workflows for Machine Learning - SF Bay Area ML
 
How Functional Programming Made Me A Better Developer
How Functional Programming Made Me A Better DeveloperHow Functional Programming Made Me A Better Developer
How Functional Programming Made Me A Better Developer
 
Fp for the oo programmer
Fp for the oo programmerFp for the oo programmer
Fp for the oo programmer
 
LINQ Inside
LINQ InsideLINQ Inside
LINQ Inside
 
Get a Little Help with Your Help Desk Application
Get a Little Help with Your Help Desk ApplicationGet a Little Help with Your Help Desk Application
Get a Little Help with Your Help Desk Application
 
U19CS101 - PPS Unit 4 PPT (1).ppt
U19CS101 - PPS Unit 4 PPT (1).pptU19CS101 - PPS Unit 4 PPT (1).ppt
U19CS101 - PPS Unit 4 PPT (1).ppt
 
Algorithms
AlgorithmsAlgorithms
Algorithms
 

Más de Scott Wlaschin

Más de 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)
 
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...
 
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)
 
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
 
Designing with Capabilities
Designing with CapabilitiesDesigning with Capabilities
Designing with Capabilities
 
Dr Frankenfunctor and the Monadster
Dr Frankenfunctor and the MonadsterDr Frankenfunctor and the Monadster
Dr Frankenfunctor and the Monadster
 
An introduction to property based testing
An introduction to property based testingAn introduction to property based testing
An introduction to property based testing
 
Swift vs. Language X
Swift vs. Language XSwift vs. Language X
Swift vs. Language X
 
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
 
Doge-driven design
Doge-driven designDoge-driven design
Doge-driven design
 
The Theory of Chains
The Theory of ChainsThe Theory of Chains
The Theory of Chains
 

Último

+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
Health
 
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdfintroduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
VishalKumarJha10
 

Último (20)

Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
 
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
 
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdfintroduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
 
Right Money Management App For Your Financial Goals
Right Money Management App For Your Financial GoalsRight Money Management App For Your Financial Goals
Right Money Management App For Your Financial Goals
 
The Guide to Integrating Generative AI into Unified Continuous Testing Platfo...
The Guide to Integrating Generative AI into Unified Continuous Testing Platfo...The Guide to Integrating Generative AI into Unified Continuous Testing Platfo...
The Guide to Integrating Generative AI into Unified Continuous Testing Platfo...
 
Software Quality Assurance Interview Questions
Software Quality Assurance Interview QuestionsSoftware Quality Assurance Interview Questions
Software Quality Assurance Interview Questions
 
Exploring the Best Video Editing App.pdf
Exploring the Best Video Editing App.pdfExploring the Best Video Editing App.pdf
Exploring the Best Video Editing App.pdf
 
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
 
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
 
Diamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with PrecisionDiamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with Precision
 
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
Direct Style Effect Systems -The Print[A] Example- A Comprehension AidDirect Style Effect Systems -The Print[A] Example- A Comprehension Aid
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
 
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
 
How To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.jsHow To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.js
 
How To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected WorkerHow To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected Worker
 
A Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxA Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docx
 
Vip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS Live
Vip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS LiveVip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS Live
Vip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS Live
 
Introducing Microsoft’s new Enterprise Work Management (EWM) Solution
Introducing Microsoft’s new Enterprise Work Management (EWM) SolutionIntroducing Microsoft’s new Enterprise Work Management (EWM) Solution
Introducing Microsoft’s new Enterprise Work Management (EWM) Solution
 
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
 
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfLearn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
 
Optimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVOptimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTV
 

The Power of Composition

  • 1. The Power Of Composition @ScottWlaschin fsharpforfunandprofit.com ^ for beginners in FP
  • 2. The Power Of Composition • The philosophy of composition • Functional programming principles – Functions and how to compose them – Types and how to compose them • Composition in practice – Two simple examples – FizzBuzz gone carbonated – A web service
  • 4. How to learn functional programming • Have a "beginner's mind" • Forget everything you know about object- oriented programming – No loops! – No variables! – No objects!
  • 5. The "Are you ready to learn FP?" test • What is a class? • What is a method? • What is a for-loop? • What is inheritance? You *must* pass this test before continuing!
  • 6. Answers! • What is a class? – Correct answer: "I don't know" • What is a method? – Correct answer: "No idea" • What is a for-loop? – Correct answer: "I couldn't tell you" • What is inheritance? – Correct answer: "Search me"
  • 8. 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
  • 10. Lego Philosophy 1. All pieces are designed to be connected 2. Connect two pieces together and get another "piece" that can still be connected 3. The pieces are reusable in many contexts
  • 11. All pieces are designed to be connected
  • 12. Connect two pieces together and get another "piece" that can still be connected
  • 13. The pieces are reusable in different contexts
  • 14. Make big things from small things in the same way
  • 15.
  • 16. Wooden RailwayTrack Philosophy 1. All pieces are designed to be connected 2. Connect two pieces together and get another "piece" that can still be connected 3. The pieces are reusable in many contexts
  • 17. All pieces are designed to be connected
  • 18. Connect two pieces together and get another "piece" that can still be connected You can keep adding and adding.
  • 19. The pieces are reusable in different contexts
  • 20. Make big things from small things in the same way
  • 21. Unix Philosophy • Write programs that do one thing well. – To do a new job, build afresh rather than complicate old programs by adding new "features". • Write programs to work together. – Expect the output of every program to become the input to another, as yet unknown, program. • Write programs to handle text streams, because that is a universal interface. All pieces are designed to be connected The pieces are reusable You don't need to create a special adapter to make connections.
  • 23. Core principles of FP Function Types are not classes Functions are things Composition everywhere
  • 24. Core FP principle: Functions are things Function
  • 25. Functions as things The Tunnel of Transformation Function apple -> banana A function is a thing which transforms inputs to outputs
  • 26. A function is a standalone thing, not attached to a class It can be used for inputs and outputs of other functions
  • 27. input A function can be an output A function is a standalone thing
  • 28. output A function can be an input A function is a standalone thing
  • 29. input output A function can be a parameter A function is a standalone thing
  • 31. Function composition Function 1 apple -> banana Function 2 banana -> cherry
  • 32. Function composition >> Function 1 apple -> banana Function 2 banana -> cherry
  • 33. Function composition New Function apple -> cherry Can't tell it was built from smaller functions! Where did the banana go? (abstraction)
  • 34. Function composition New Function apple -> cherry A Very Important Point: For composition to work properly: • Data must be immutable • Functions must be self-contained, with no strings attached: no side-effects, no I/O, no globals, etc
  • 35. let add1 x = x + 1 let double x = x + x let add1_double = add1 >> double let x = add1_double 5 // 12 Composition DoubleAdd1
  • 36. let add1_double_square = add1 >> double >> square let x = add1_double_square 5 // 144 Composition DoubleAdd1 Square
  • 38. add1 5 // = 6 double (add1 5) // = 12 square (double (add1 5)) // = 144
  • 39. 5 |> add1 // = 6 5 |> add1 |> double // = 12 5 |> add1 |> double |> square // = 144 add1 double square5 6 12 144
  • 40. Building big things from functions It's compositions all the way up
  • 42. 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
  • 46.
  • 47.
  • 48. • "monoids" – for combining strings, lists, etc. • "monads" – for composing functions with effects • CategoryTheory – or, "Composition Theory" More kinds of composition for functional programmers…
  • 49. Core FP principle: Types are not classes
  • 50. 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
  • 51. 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
  • 52. 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
  • 53. 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
  • 54. 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
  • 55. 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
  • 58. New types are built from smaller types by: Composing with “AND” Composing with “OR”
  • 59. Example: pairs, tuples, records FruitSalad = One each of and and Compose with “AND” type FruitSalad = { Apple: AppleVariety Banana: BananaVariety Cherry: CherryVariety }
  • 60. Snack = or or Compose with “OR” type Snack = | Apple of AppleVariety | Banana of BananaVariety | Cherry of CherryVariety
  • 61. Real world example of type composition
  • 62. Example of some requirements: We accept three forms of payment: Cash, Check, or Card. For Cash we don't need any extra information For Checks we need a check number For Cards we need a card type and card number
  • 63. interface IPaymentMethod {..} class Cash() : IPaymentMethod {..} class Check(int checkNo): 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:
  • 64. type CheckNumber = int type CardNumber = string In F# you would probably implement by composing types, like this:
  • 65. type CheckNumber = ... type CardNumber = … type CardType = Visa | Mastercard type CreditCardInfo = { CardType : CardType CardNumber : CardNumber }
  • 66. type CheckNumber = ... type CardNumber = ... type CardType = ... type CreditCardInfo = ... type PaymentMethod = | Cash | Check of CheckNumber | Card of CreditCardInfo
  • 67. type CheckNumber = ... type CardNumber = ... type CardType = ... type CreditCardInfo = ... type PaymentMethod = | Cash | Check of CheckNumber | Card of CreditCardInfo type PaymentAmount = decimal type Currency = EUR | USD
  • 68. type CheckNumber = ... type CardNumber = ... type CardType = ... type CreditCardInfo = ... type PaymentMethod = | Cash | Check of CheckNumber | Card of CreditCardInfo type PaymentAmount = decimal type Currency = EUR | USD type Payment = { Amount : PaymentAmount Currency: Currency Method: PaymentMethod }
  • 69. FP design principle: Types are executable documentation
  • 70. type Deal = Deck –› (Deck * Card) type PickupCard = (Hand * Card) –› Hand Types are executable documentation type Suit = Club | Diamond | Spade | Heart type Rank = Two | Three | Four | Five | Six | Seven | Eight | Nine |Ten | Jack | Queen | King | Ace type Card = Suit * 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. Types are executable documentation type CardType =Visa | Mastercard type CardNumber = CardNumber of string type CheckNumber = CheckNumber of int type PaymentMethod = | Cash | Check of CheckNumber | Card of CardType * CardNumber
  • 72. A big topic and not enough time   More on DDD and designing with types at fsharpforfunandprofit.com/ddd
  • 74. Think of a number • Think of a number. • Add one to it. • Square it. • Subtract one. • Divide by the number you first thought of. • Subtract the number you first thought of. • The answer is TWO!
  • 75. Think of a number AddOne SquareItSubtractOne DivideByTheNumberYouThoughtOf SubtractTheNumberYouThoughtOf TheNumberYouThoughtOf Answer
  • 76. let thinkOfANumber numberYouThoughtOf = // define a function for each step let addOne x = x + 1 let squareIt x = x * x let subtractOne x = x - 1 let divideByTheNumberYouThoughtOf x = x / numberYouThoughtOf let subtractTheNumberYouThoughtOf x = x - numberYouThoughtOf // then combine them using piping numberYouThoughtOf |> addOne |> squareIt |> subtractOne |> divideByTheNumberYouThoughtOf |> subtractTheNumberYouThoughtOf
  • 80. function A and B Easy!
  • 81. ... But here is a challenge
  • 82. function AInput Output function BInput Output 1 Output 2 function C Input 1 Output Input 2
  • 83. function AInput Output function BInput Output 1 Output 2 Challenge: How can we compose these?
  • 84. function AInput Output function C Input 1 Output Input 2 Challenge: How can we compose these?
  • 86. To Roman Numerals • Task: convert an integer to Roman Numerals • V = 5, X = 10, C = 100 etc
  • 87. 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" – Replace five "C"s with a "D" – Replace two "D"s with a "M"
  • 88. The Replace function oldValue outputString newValue inputString Replace
  • 89. Uh-oh! Composition problem Replace I / V Replace V / X Replace X / L 
  • 90. Bad news: Composition patterns only work for functions that have one parameter! 
  • 91. Good news! Every function can be turned into a one parameter function 
  • 92. Haskell Curry We named this technique after him
  • 93. Input A Uncurried Function Input B Output C Curried Function Input A Intermediate Function Output CInput B What is currying? after currying Currying means that *every* function can be converted to a series of one input functions
  • 94. Replace Before currying let replace oldValue newValue inputStr = inputStr.Replace(oldValue,newValue)
  • 95. Replace Old New Old New After currying let replace oldValue newValue = fun inputStr -> inputStr.Replace(oldValue,newValue)
  • 96. Partial Application Replace ReplaceOldNew Old New Old New let replace_IIIII_V = replace "IIIII" "V" // replace_IIIII_V is a function let replace_VV_X = replace "VV" "X" // replace_VV_X is a function Only 2 parameters passed in
  • 97. To Roman Numerals integer etc Replicate "I" Replace_IIIII_V Replace_VV_X Replace_XXXXX_L
  • 98. let toRomanNumerals number = let replace_IIIII_V = replace "IIIII" "V" let replace_VV_X = replace "VV" "X" let replace_XXXXX_L = replace "XXXXX" "L" let replace_LL_C = replace "LL" "C" let replace_CCCCC_D = replace "CCCCC" "D" let replace_DD_M = replace "DD" "M" String.replicate number "I" |> replace_IIIII_V |> replace_VV_X |> replace_XXXXX_L |> replace_LL_C |> replace_CCCCC_D |> replace_DD_M
  • 99. Inline Partial Application let add x y = x + y let multiply x y = x * y 5 |> add 2 |> multiply 2 Piping "inline" partial application
  • 100. Inline Partial Application let add x y = x + y let multiply x y = x * y [1..10] |> List.map (add 2) |> List.map (multiply 2) Two "inline" partial applications
  • 101. let toRomanNumerals number = String.replicate number "I" |> replace "IIIII" "V" |> replace "VV" "X" |> replace "XXXXX" "L" |> replace "LL" "C" |> replace "CCCCC" "D" |> replace "DD" "M" With inline partial application
  • 102. let toRomanNumerals number = String.replicate number "I" |> replace "IIIII" "V" |> replace "VV" "X" |> replace "XXXXX" "L" |> replace "LL" "C" |> replace "CCCCC" "D" |> replace "DD" "M" With inline partial application // can easily add new segments to the pipeline |> replace "VIIII" "IX" |> replace "IIII" "IV" |> replace "LXXXX" "XC"
  • 103. functionInput Output function Input 1 Output Input 2 Challenge: How can we compose these?
  • 105. FizzBuzz definition • Write a program that prints the numbers from 1 to 100 • But: – For multiples of three print "Fizz" instead – For multiples of five print "Buzz" instead – For multiples of both three and five print "FizzBuzz" instead.
  • 106. let fizzBuzz max = for n in [1..max] do 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 A simple implementation
  • 107. Pipeline implementation Handle 3 case Handle 5 case number Answer Handle 15 case Handle remaining
  • 108. number Handle case Carbonated (e.g. "Fizz", "Buzz") Uncarbonated (e.g. 2, 7, 13)
  • 110. type CarbonationResult = | Uncarbonated of int // unprocessed | Carbonated of string // "Fizz", Buzz", etc FizzBuzz core let carbonate divisor label n = if (isDivisibleBy n divisor) then Carbonated label else Uncarbonated n Idea from http://weblog.raganwald.com/2007/01/dont-overthink-fizzbuzz.html
  • 111. 12 |> carbonate 3 "Fizz" // Carbonated "Fizz" 10 |> carbonate 3 "Fizz" // Uncarbonated 10 10 |> carbonate 5 "Buzz" // Carbonated "Buzz"
  • 113. How do we compose these?
  • 114.
  • 115. >> >> Composing one-track functions is fine...
  • 116. >> >> ... and composing two-track functions is fine...
  • 117.   ... but composing points/switches is not allowed!
  • 118. let fizzbuzz n = let result15 = n |> carbonate 15 "FizzBuzz" match result15 with | Carbonated str -> str | Uncarbonated n -> let result3 = n |> carbonate 3 "Fizz" match result3 with | Carbonated str -> str | Uncarbonated n -> let result5 = n |> carbonate 5 "Buzz" match result5 with | Carbonated str -> str | Uncarbonated n -> string n // convert to string First implementation attempt
  • 119. let fizzbuzz n = let result15 = n |> carbonate 15 "FizzBuzz" match result15 with | Carbonated str -> str | Uncarbonated n -> let result3 = n |> carbonate 3 "Fizz" match result3 with | Carbonated str -> str | Uncarbonated n -> let result5 = n |> carbonate 5 "Buzz" match result5 with | Carbonated str -> str | Uncarbonated n -> // do something with Uncarbonated value
  • 120. let fizzbuzz n = let result15 = n |> carbonate 15 "FizzBuzz" match result15 with | Carbonated str -> str | Uncarbonated n -> let result3 = n |> carbonate 3 "Fizz" match result3 with | Carbonated str -> str | Uncarbonated n -> // do something with Uncarbonated value
  • 121. let fizzbuzz n = let result15 = n |> carbonate 15 "FizzBuzz" match result15 with | Carbonated str -> str | Uncarbonated n -> // do something with Uncarbonated value
  • 122. if Carbonated // return the string if Uncarbonated then // do something with the number
  • 123. let ifUncarbonatedDo f result = match result with | Carbonated str -> Carbonated str | Uncarbonated n -> f n
  • 124. let fizzbuzz n = n |> carbonate 15 "FizzBuzz" |> ifUncarbonatedDo (carbonate 3 "Fizz") |> ifUncarbonatedDo (carbonate 5 "Buzz") |> carbonateRemaining let carbonateRemaining result = match result with | Carbonated str -> str | Uncarbonated n -> string(n)
  • 126. Another composition problem List of numbers FizzBizz for one number 
  • 127. Solution: the "map" transformer List input List outputFizzBizz for lists FizzBizz for one number List.map
  • 128. // final version of FizzBuzz let fizzbuzz100 = [1..100] |> List.map fizzBuzz |> List.iter (printfn "%s") // I/O only at end let fizzbuzz n = n |> carbonate 15 "FizzBuzz" |> ifUncarbonatedDo (carbonate 3 "Fizz") |> ifUncarbonatedDo (carbonate 5 "Buzz") |> carbonateRemaining
  • 130. Is there a general solution to handling functions like this?
  • 131. Yes! “Bind” is the answer! Bind all the things!
  • 132. Two-track input Two-track output One-track input Two-track output  
  • 135. let bind nextFunction result = match result with | Uncarbonated n -> nextFunction n | Carbonated str -> Carbonated str Two-track input Two-track output
  • 136. let bind nextFunction result = match result with | Uncarbonated n -> nextFunction n | Carbonated str -> Carbonated str Two-track input Two-track output
  • 137. let bind nextFunction result = match result with | Uncarbonated n -> nextFunction n | Carbonated str -> Carbonated str Two-track input Two-track output
  • 138. let bind nextFunction result = match result with | Uncarbonated n -> nextFunction n | Carbonated str -> Carbonated str Two-track input Two-track output
  • 139. 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
  • 140. Example: Using bind to chain tasks
  • 141. When task completesWait Wait a.k.a "promise", "future"
  • 142. 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
  • 143. let bind f task = task.WhenFinished (fun taskResult -> f taskResult) let taskExample input = startTask input |> bind startAnotherTask |> bind startThirdTask |> bind ... Rewritten using bind:
  • 144. let ( >>= ) x f = x |> bind let taskExample input = startTask input >>= startAnotherTask >>= startThirdTask >>= ... Rewritten using >>= A common symbol for "bind"
  • 146. Example of scenario with errors Name is blank Email not valid Validate request Canonicalize email Fetch existing user record Update existing user record User not found Db error Authorization error Timeout
  • 148. Validate Canonicalize Generates a possible error Always succeeds
  • 149. Validate Canonicalize DbFetch Generates a possible error Generates a possible errorAlways succeeds
  • 150. Validate Canonicalize DbFetch DbUpdate Generates a possible error Generates a possible errorAlways succeeds Doesn't return How can we glue these mismatched functions together?
  • 154. Validate Canonicalize DbFetch DbUpdate Now we *can* compose them easily! map bind tee, then map
  • 156. =+ Result is same kind of thing Kleisli Composition
  • 157. Async<HttpContext option>HttpContext A "WebPart" (suave.io library) See suave.io site for more
  • 158. =>=> Result is another WebPart so you can repeat WebPart Composition Kleisli composition symbol
  • 159. path "/hello" >=> OK "Hello" // a WebPart Checks request path (might fail) Sets response
  • 160. choose [ path "/hello" >=> OK "Hello" path "/goodbye" >=> OK "Goodbye" ] Picks first WebPart that succeeds
  • 161. GET >=> choose [ path "/hello" >=> OK "Hello" path "/goodbye" >=> OK "Goodbye" ] Only succeeds if request is a GET
  • 162. let app = choose [ GET >=> choose [ path "/hello" >=> OK "Hello" path "/goodbye" >=> OK "Goodbye" ] POST >=> choose [ path "/hello" >=> OK "Hello POST" path "/goodbye" >=> OK "Goodbye POST" ] ] startWebServer defaultConfig app A complete web app
  • 163. Http Response Http Request As I promised – no classes, no loops, etc!
  • 164. Review • The philosophy of composition – Connectable, no adapters, reusable parts • FP principles: – Composable functions – Composable types • Basic composition – Composition with ">>" – Piping with "|>" • Using partial application to help composition • Monads and monadic functions – Composition using "bind" / ">>=" – Kleisli composition using ">=>"
  • 165. Slides and video here fsharpforfunandprofit.com/composition Thank you! "Domain modelling Made Functional" book fsharpforfunandprofit.com/books @ScottWlaschin Me on twitter fsharpforfunandprofit.com/videos