the power of composition
TRANSCRIPT
![Page 1: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/1.jpg)
The Power Of Composition
@ScottWlaschin
fsharpforfunandprofit.com
^ for beginners in FP
![Page 2: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/2.jpg)
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
![Page 3: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/3.jpg)
PREREQUISITES
![Page 4: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/4.jpg)
How to learn functional programming
• Have a "beginner's mind"
• Forget everything you know about object-
oriented programming
– No loops!
– No variables!
– No objects!
![Page 5: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/5.jpg)
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!
![Page 6: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/6.jpg)
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"
![Page 7: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/7.jpg)
THE PHILOSOPHY OF
COMPOSITION
![Page 8: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/8.jpg)
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
![Page 9: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/9.jpg)
Lego
Philosophy
![Page 10: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/10.jpg)
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
![Page 11: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/11.jpg)
All pieces are designed to be connected
![Page 12: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/12.jpg)
Connect two pieces together and get another "piece" that can still be connected
![Page 13: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/13.jpg)
The pieces are reusable in different contexts
![Page 14: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/14.jpg)
Make big things from small things in the same way
![Page 15: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/15.jpg)
![Page 16: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/16.jpg)
Wooden Railway Track 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
![Page 17: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/17.jpg)
All pieces are designed to be connected
![Page 18: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/18.jpg)
Connect two pieces together and get another "piece" that can still be connected
You can keep adding and adding.
![Page 19: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/19.jpg)
The pieces are reusable in different contexts
![Page 20: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/20.jpg)
Make big things from small things in the same way
![Page 21: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/21.jpg)
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.
![Page 22: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/22.jpg)
THE PRINCIPLES OF
FUNCTIONAL PROGRAMMING
![Page 23: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/23.jpg)
Core principles of FP
Function
Types are not classes
Functions are things
Composition everywhere
![Page 24: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/24.jpg)
Core FP principle:
Functions are things
Function
![Page 25: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/25.jpg)
Functions as things
The Tunnel of Transformation Function
apple -> banana
A function is a thing which transforms inputs to outputs
![Page 26: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/26.jpg)
A function is a standalone thing,
not attached to a class
It can be used for inputs and outputs
of other functions
![Page 27: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/27.jpg)
input
A function can be an output
A function is a standalone thing
![Page 28: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/28.jpg)
output
A function can be an input
A function is a standalone thing
![Page 29: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/29.jpg)
input output
A function can be a parameter
A function is a standalone thing
![Page 30: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/30.jpg)
Core FP principle:
Composition everywhere
![Page 31: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/31.jpg)
Function composition
Function 1
apple -> banana
Function 2
banana -> cherry
![Page 32: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/32.jpg)
Function composition
>> Function 1
apple -> banana Function 2
banana -> cherry
![Page 33: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/33.jpg)
Function composition
New Function
apple -> cherry
Can't tell it was built from smaller functions!
Where did the banana go? (abstraction)
![Page 34: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/34.jpg)
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
![Page 35: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/35.jpg)
let add1 x = x + 1 let double x = x + x let add1_double = add1 >> double let x = add1_double 5 // 12
Composition
Double Add1
![Page 36: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/36.jpg)
let add1_double_square = add1 >> double >> square let x = add1_double_square 5 // 144
Composition
Double Add1 Square
![Page 37: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/37.jpg)
Piping
![Page 38: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/38.jpg)
add1 5 // = 6 double (add1 5) // = 12 square (double (add1 5)) // = 144
![Page 39: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/39.jpg)
5 |> add1 // = 6 5 |> add1 |> double // = 12 5 |> add1 |> double |> square // = 144
add1 double square 5 6 12 144
![Page 40: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/40.jpg)
Building big things from functions It's compositions all the way up
![Page 41: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/41.jpg)
Low-level operation
ToUpper string string
![Page 42: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/42.jpg)
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
![Page 43: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/43.jpg)
Service
Use-case
UpdateProfileData ChangeProfile
Result
ChangeProfile
Request
Service Service
![Page 44: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/44.jpg)
Use-case
Web application
Http
Response
Http
Request
Use-case Use-case
![Page 45: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/45.jpg)
Http
Response Http
Request
![Page 46: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/46.jpg)
![Page 47: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/47.jpg)
![Page 48: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/48.jpg)
• "monoids"
– for combining strings, lists, etc.
• "monads"
– for composing functions with effects
• Category Theory
– or, "Composition Theory"
More kinds of composition for functional programmers…
![Page 49: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/49.jpg)
Core FP principle:
Types are not classes
![Page 50: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/50.jpg)
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
![Page 51: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/51.jpg)
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
![Page 52: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/52.jpg)
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
![Page 53: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/53.jpg)
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
Gordon Wood
A type is a just a name
for a set of things
![Page 54: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/54.jpg)
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
![Page 55: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/55.jpg)
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
![Page 56: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/56.jpg)
Composition everywhere:
Types can be composed too
![Page 57: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/57.jpg)
Algebraic type system
![Page 58: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/58.jpg)
New types are built from smaller types by:
Composing with “AND”
Composing with “OR”
![Page 59: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/59.jpg)
Example: pairs, tuples, records FruitSalad = One each of and and
Compose with “AND”
type FruitSalad = { Apple: AppleVariety Banana: BananaVariety Cherry: CherryVariety }
![Page 60: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/60.jpg)
Snack = or or
Compose with “OR”
type Snack = | Apple of AppleVariety | Banana of BananaVariety | Cherry of CherryVariety
![Page 61: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/61.jpg)
Real world example
of type composition
![Page 62: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/62.jpg)
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
![Page 63: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/63.jpg)
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:
![Page 64: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/64.jpg)
type CheckNumber = int
type CardNumber = string
In F# you would probably implement by composing types, like this:
![Page 65: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/65.jpg)
type CheckNumber = ...
type CardNumber = …
type CardType = Visa | Mastercard
type CreditCardInfo = {
CardType : CardType
CardNumber : CardNumber
}
![Page 66: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/66.jpg)
type CheckNumber = ...
type CardNumber = ...
type CardType = ...
type CreditCardInfo = ...
type PaymentMethod =
| Cash
| Check of CheckNumber
| Card of CreditCardInfo
![Page 67: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/67.jpg)
type CheckNumber = ...
type CardNumber = ...
type CardType = ...
type CreditCardInfo = ...
type PaymentMethod =
| Cash
| Check of CheckNumber
| Card of CreditCardInfo
type PaymentAmount = decimal
type Currency = EUR | USD
![Page 68: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/68.jpg)
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 }
![Page 69: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/69.jpg)
FP design principle:
Types are executable documentation
![Page 70: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/70.jpg)
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!
![Page 71: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/71.jpg)
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
![Page 72: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/72.jpg)
A big topic and not enough time
More on DDD and designing with types at
fsharpforfunandprofit.com/ddd
![Page 73: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/73.jpg)
BASIC COMPOSITION:
THINK OF A NUMBER
![Page 74: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/74.jpg)
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!
![Page 75: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/75.jpg)
Think of a number
AddOne
SquareIt SubtractOne
DivideByTheNumberYouThoughtOf
SubtractTheNumberYouThoughtOf
TheNumberYouThoughtOf
Answer
![Page 76: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/76.jpg)
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
![Page 77: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/77.jpg)
IT'S NOT ALWAYS THIS
EASY…
![Page 78: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/78.jpg)
function A function B Compose
![Page 79: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/79.jpg)
function A function B
![Page 80: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/80.jpg)
function A and B
Easy!
![Page 81: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/81.jpg)
... But here is a challenge
![Page 82: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/82.jpg)
function A Input Output
function B Input Output 1
Output 2
function C Input 1 Output Input 2
![Page 83: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/83.jpg)
function A Input Output
function B Input Output 1
Output 2
Challenge: How can we compose these?
![Page 84: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/84.jpg)
function A Input Output
function C Input 1 Output Input 2
Challenge: How can we compose these?
![Page 85: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/85.jpg)
COMPOSING MULTIPLE INPUTS:
ROMAN NUMERALS
![Page 86: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/86.jpg)
To Roman Numerals
• Task: convert an integer to Roman Numerals
• V = 5, X = 10, C = 100 etc
![Page 87: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/87.jpg)
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"
![Page 88: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/88.jpg)
The Replace function
oldValue outputString newValue
inputString
Replace
![Page 89: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/89.jpg)
Uh-oh! Composition problem
Replace I / V Replace V / X Replace X / L
![Page 90: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/90.jpg)
Bad news:
Composition patterns
only work for functions that
have one parameter!
![Page 91: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/91.jpg)
Good news!
Every function can be turned into
a one parameter function
![Page 92: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/92.jpg)
Haskell Curry
We named this technique after him
![Page 93: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/93.jpg)
Input A Uncurried Function
Input B Output C
Curried Function
Input A Intermediate
Function Output C Input B
What is currying?
after currying
Currying means that *every* function can be converted to a series of one input functions
![Page 94: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/94.jpg)
Replace
Before currying
let replace oldValue newValue inputStr = inputStr.Replace(oldValue,newValue)
![Page 95: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/95.jpg)
Replace Old New
Old New
After currying
let replace oldValue newValue = fun inputStr -> inputStr.Replace(oldValue,newValue)
![Page 96: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/96.jpg)
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
![Page 97: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/97.jpg)
To Roman Numerals
integer
etc
Replicate "I"
Replace_IIIII_V
Replace_VV_X
Replace_XXXXX_L
![Page 98: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/98.jpg)
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
![Page 99: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/99.jpg)
Inline Partial Application
let add x y = x + y let multiply x y = x * y 5 |> add 2 |> multiply 2
Piping
"inline" partial application
![Page 100: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/100.jpg)
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
![Page 101: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/101.jpg)
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
![Page 102: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/102.jpg)
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"
![Page 103: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/103.jpg)
function Input Output
function Input 1 Output Input 2
Challenge: How can we compose these?
![Page 104: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/104.jpg)
COMPOSING MULTIPLE OUTPUTS:
FIZZBUZZ
![Page 105: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/105.jpg)
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.
![Page 106: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/106.jpg)
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
![Page 107: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/107.jpg)
Pipeline implementation
Handle 3 case
Handle 5 case
number
Answer
Handle 15 case
Handle remaining
![Page 108: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/108.jpg)
number Handle case
Carbonated
(e.g. "Fizz", "Buzz")
Uncarbonated
(e.g. 2, 7, 13)
![Page 109: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/109.jpg)
Uncarbonated
Carbonated
Input ->
![Page 110: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/110.jpg)
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
![Page 111: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/111.jpg)
12 |> carbonate 3 "Fizz" // Carbonated "Fizz"
10 |> carbonate 3 "Fizz" // Uncarbonated 10
10 |> carbonate 5 "Buzz" // Carbonated "Buzz"
![Page 112: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/112.jpg)
If Uncarbonated
If Carbonated
bypass
How to we compose them?
![Page 113: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/113.jpg)
How do we compose these?
![Page 114: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/114.jpg)
![Page 115: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/115.jpg)
>> >>
Composing one-track functions is fine...
![Page 116: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/116.jpg)
>> >>
... and composing two-track functions is fine...
![Page 117: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/117.jpg)
... but composing points/switches is not allowed!
![Page 118: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/118.jpg)
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
![Page 119: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/119.jpg)
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
![Page 120: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/120.jpg)
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
![Page 121: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/121.jpg)
let fizzbuzz n =
let result15 = n |> carbonate 15 "FizzBuzz"
match result15 with
| Carbonated str ->
str
| Uncarbonated n ->
// do something with Uncarbonated value
![Page 122: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/122.jpg)
if Carbonated // return the string if Uncarbonated then // do something with the number
![Page 123: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/123.jpg)
let ifUncarbonatedDo f result = match result with | Carbonated str -> Carbonated str | Uncarbonated n -> f n
![Page 124: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/124.jpg)
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)
![Page 125: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/125.jpg)
MAKING LOOPS
COMPOSABLE
![Page 126: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/126.jpg)
Another composition problem
List of
numbers FizzBizz for one number
![Page 127: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/127.jpg)
Solution: the "map" transformer
List input List output FizzBizz for lists
FizzBizz for one number
List.map
![Page 128: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/128.jpg)
// 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
![Page 129: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/129.jpg)
THE M-WORD
![Page 130: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/130.jpg)
Is there a general solution to
handling functions like this?
![Page 131: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/131.jpg)
Yes! “Bind” is the answer!
Bind all the things!
![Page 132: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/132.jpg)
Two-track input Two-track output
One-track input Two-track output
![Page 133: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/133.jpg)
Two-track input Two-track output
![Page 134: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/134.jpg)
Two-track input Two-track output
![Page 135: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/135.jpg)
let bind nextFunction result = match result with | Uncarbonated n -> nextFunction n | Carbonated str -> Carbonated str
Two-track input Two-track output
![Page 136: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/136.jpg)
let bind nextFunction result = match result with | Uncarbonated n -> nextFunction n | Carbonated str -> Carbonated str
Two-track input Two-track output
![Page 137: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/137.jpg)
let bind nextFunction result = match result with | Uncarbonated n -> nextFunction n | Carbonated str -> Carbonated str
Two-track input Two-track output
![Page 138: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/138.jpg)
let bind nextFunction result = match result with | Uncarbonated n -> nextFunction n | Carbonated str -> Carbonated str
Two-track input Two-track output
![Page 139: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/139.jpg)
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
![Page 140: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/140.jpg)
Example:
Using bind to chain tasks
![Page 141: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/141.jpg)
When task completes Wait Wait
a.k.a "promise", "future"
![Page 142: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/142.jpg)
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
![Page 143: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/143.jpg)
let bind f task = task.WhenFinished (fun taskResult -> f taskResult)
let taskExample input = startTask input |> bind startAnotherTask |> bind startThirdTask |> bind ...
Rewritten using bind:
![Page 144: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/144.jpg)
let ( >>= ) x f = x |> bind
let taskExample input = startTask input >>= startAnotherTask >>= startThirdTask >>= ...
Rewritten using >>=
A common symbol for "bind"
![Page 145: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/145.jpg)
Example: Composing error-generating functions
![Page 146: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/146.jpg)
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
![Page 147: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/147.jpg)
Validate
Generates a possible error
![Page 148: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/148.jpg)
Validate Canonicalize
Generates a possible error Always succeeds
![Page 149: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/149.jpg)
Validate Canonicalize DbFetch
Generates a possible error Generates a possible error Always succeeds
![Page 150: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/150.jpg)
Validate Canonicalize DbFetch DbUpdate
Generates a possible error Generates a possible error Always succeeds Doesn't return
How can we glue these mismatched functions together?
![Page 151: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/151.jpg)
map
Converting everything to two-track
![Page 152: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/152.jpg)
bind
map
Converting everything to two-track
![Page 153: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/153.jpg)
bind
map
tee map
Converting everything to two-track
![Page 154: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/154.jpg)
Validate Canonicalize DbFetch DbUpdate
Now we *can* compose them easily!
map bind tee, then map
![Page 155: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/155.jpg)
KLEISLI COMPOSITION:
WEB SERVICE
![Page 156: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/156.jpg)
= +
Result is same kind of thing
Kleisli Composition
![Page 157: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/157.jpg)
Async<HttpContext option> HttpContext
A "WebPart" (suave.io library)
See suave.io site for more
![Page 158: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/158.jpg)
= >=>
Result is another WebPart so you can repeat
WebPart Composition
Kleisli composition symbol
![Page 159: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/159.jpg)
path "/hello" >=> OK "Hello" // a WebPart
Checks request path (might fail)
Sets response
![Page 160: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/160.jpg)
choose [ path "/hello" >=> OK "Hello" path "/goodbye" >=> OK "Goodbye" ]
Picks first WebPart that succeeds
![Page 161: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/161.jpg)
GET >=> choose [ path "/hello" >=> OK "Hello" path "/goodbye" >=> OK "Goodbye" ]
Only succeeds if request is a GET
![Page 162: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/162.jpg)
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
![Page 163: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/163.jpg)
Http
Response Http
Request
As I promised – no classes, no loops, etc!
![Page 164: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/164.jpg)
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 ">=>"
![Page 165: The Power of Composition](https://reader034.vdocuments.mx/reader034/viewer/2022051720/5aaddef97f8b9ae23a8b47ad/html5/thumbnails/165.jpg)
Slides and video here
fsharpforfunandprofit.com/composition
Thank you!
"Domain modelling Made Functional" book
fsharpforfunandprofit.com/books
@ScottWlaschin Me on twitter
fsharpforfunandprofit.com/videos