165
The Power Of Composition @ScottWlaschin fsharpforfunandprofit.com ^ for beginners in FP

The Power of Composition

Embed Size (px)

Citation preview

Page 1: The Power of Composition

The Power Of Composition

@ScottWlaschin

fsharpforfunandprofit.com

^ for beginners in FP

Page 2: The Power of Composition

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

PREREQUISITES

Page 4: The Power of Composition

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

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

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

THE PHILOSOPHY OF

COMPOSITION

Page 8: The Power 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

Page 9: The Power of Composition

Lego

Philosophy

Page 10: The Power of Composition

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

All pieces are designed to be connected

Page 12: The Power of Composition

Connect two pieces together and get another "piece" that can still be connected

Page 13: The Power of Composition

The pieces are reusable in different contexts

Page 14: The Power of Composition

Make big things from small things in the same way

Page 15: The Power of Composition
Page 16: The Power of Composition

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

All pieces are designed to be connected

Page 18: The Power of Composition

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

The pieces are reusable in different contexts

Page 20: The Power of Composition

Make big things from small things in the same way

Page 21: The Power of Composition

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

THE PRINCIPLES OF

FUNCTIONAL PROGRAMMING

Page 23: The Power of Composition

Core principles of FP

Function

Types are not classes

Functions are things

Composition everywhere

Page 24: The Power of Composition

Core FP principle:

Functions are things

Function

Page 25: The Power of Composition

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

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

input

A function can be an output

A function is a standalone thing

Page 28: The Power of Composition

output

A function can be an input

A function is a standalone thing

Page 29: The Power of Composition

input output

A function can be a parameter

A function is a standalone thing

Page 30: The Power of Composition

Core FP principle:

Composition everywhere

Page 31: The Power of Composition

Function composition

Function 1

apple -> banana

Function 2

banana -> cherry

Page 32: The Power of Composition

Function composition

>> Function 1

apple -> banana Function 2

banana -> cherry

Page 33: The Power of Composition

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

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

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

let add1_double_square = add1 >> double >> square let x = add1_double_square 5 // 144

Composition

Double Add1 Square

Page 37: The Power of Composition

Piping

Page 38: The Power of Composition

add1 5 // = 6 double (add1 5) // = 12 square (double (add1 5)) // = 144

Page 39: The Power of Composition

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

Building big things from functions It's compositions all the way up

Page 41: The Power of Composition

Low-level operation

ToUpper string string

Page 42: The Power of Composition

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

Service

Use-case

UpdateProfileData ChangeProfile

Result

ChangeProfile

Request

Service Service

Page 44: The Power of Composition

Use-case

Web application

Http

Response

Http

Request

Use-case Use-case

Page 45: The Power of Composition

Http

Response Http

Request

Page 46: The Power of Composition
Page 47: The Power of Composition
Page 48: The Power of Composition

• "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

Core FP principle:

Types are not classes

Page 50: The Power of Composition

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

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

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

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

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

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

Composition everywhere:

Types can be composed too

Page 57: The Power of Composition

Algebraic type system

Page 58: The Power of Composition

New types are built from smaller types by:

Composing with “AND”

Composing with “OR”

Page 59: The Power of Composition

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

Snack = or or

Compose with “OR”

type Snack = | Apple of AppleVariety | Banana of BananaVariety | Cherry of CherryVariety

Page 61: The Power of Composition

Real world example

of type composition

Page 62: The Power of 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

Page 63: The Power of Composition

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

type CheckNumber = int

type CardNumber = string

In F# you would probably implement by composing types, like this:

Page 65: The Power of Composition

type CheckNumber = ...

type CardNumber = …

type CardType = Visa | Mastercard

type CreditCardInfo = {

CardType : CardType

CardNumber : CardNumber

}

Page 66: The Power of Composition

type CheckNumber = ...

type CardNumber = ...

type CardType = ...

type CreditCardInfo = ...

type PaymentMethod =

| Cash

| Check of CheckNumber

| Card of CreditCardInfo

Page 67: The Power of Composition

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

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

FP design principle:

Types are executable documentation

Page 70: The Power of Composition

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

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

A big topic and not enough time

More on DDD and designing with types at

fsharpforfunandprofit.com/ddd

Page 73: The Power of Composition

BASIC COMPOSITION:

THINK OF A NUMBER

Page 74: The Power of Composition

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

Think of a number

AddOne

SquareIt SubtractOne

DivideByTheNumberYouThoughtOf

SubtractTheNumberYouThoughtOf

TheNumberYouThoughtOf

Answer

Page 76: The Power of Composition

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

IT'S NOT ALWAYS THIS

EASY…

Page 78: The Power of Composition

function A function B Compose

Page 79: The Power of Composition

function A function B

Page 80: The Power of Composition

function A and B

Easy!

Page 81: The Power of Composition

... But here is a challenge

Page 82: The Power of Composition

function A Input Output

function B Input Output 1

Output 2

function C Input 1 Output Input 2

Page 83: The Power of Composition

function A Input Output

function B Input Output 1

Output 2

Challenge: How can we compose these?

Page 84: The Power of Composition

function A Input Output

function C Input 1 Output Input 2

Challenge: How can we compose these?

Page 85: The Power of Composition

COMPOSING MULTIPLE INPUTS:

ROMAN NUMERALS

Page 86: The Power of Composition

To Roman Numerals

• Task: convert an integer to Roman Numerals

• V = 5, X = 10, C = 100 etc

Page 87: The Power of Composition

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

The Replace function

oldValue outputString newValue

inputString

Replace

Page 89: The Power of Composition

Uh-oh! Composition problem

Replace I / V Replace V / X Replace X / L

Page 90: The Power of Composition

Bad news:

Composition patterns

only work for functions that

have one parameter!

Page 91: The Power of Composition

Good news!

Every function can be turned into

a one parameter function

Page 92: The Power of Composition

Haskell Curry

We named this technique after him

Page 93: The Power of Composition

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

Replace

Before currying

let replace oldValue newValue inputStr = inputStr.Replace(oldValue,newValue)

Page 95: The Power of Composition

Replace Old New

Old New

After currying

let replace oldValue newValue = fun inputStr -> inputStr.Replace(oldValue,newValue)

Page 96: The Power of Composition

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

To Roman Numerals

integer

etc

Replicate "I"

Replace_IIIII_V

Replace_VV_X

Replace_XXXXX_L

Page 98: The Power of Composition

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

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

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

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

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

function Input Output

function Input 1 Output Input 2

Challenge: How can we compose these?

Page 104: The Power of Composition

COMPOSING MULTIPLE OUTPUTS:

FIZZBUZZ

Page 105: The Power of Composition

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

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

Pipeline implementation

Handle 3 case

Handle 5 case

number

Answer

Handle 15 case

Handle remaining

Page 108: The Power of Composition

number Handle case

Carbonated

(e.g. "Fizz", "Buzz")

Uncarbonated

(e.g. 2, 7, 13)

Page 109: The Power of Composition

Uncarbonated

Carbonated

Input ->

Page 110: The Power of Composition

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

12 |> carbonate 3 "Fizz" // Carbonated "Fizz"

10 |> carbonate 3 "Fizz" // Uncarbonated 10

10 |> carbonate 5 "Buzz" // Carbonated "Buzz"

Page 112: The Power of Composition

If Uncarbonated

If Carbonated

bypass

How to we compose them?

Page 113: The Power of Composition

How do we compose these?

Page 114: The Power of Composition
Page 115: The Power of Composition

>> >>

Composing one-track functions is fine...

Page 116: The Power of Composition

>> >>

... and composing two-track functions is fine...

Page 117: The Power of Composition

... but composing points/switches is not allowed!

Page 118: The Power of Composition

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

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

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

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

if Carbonated // return the string if Uncarbonated then // do something with the number

Page 123: The Power of Composition

let ifUncarbonatedDo f result = match result with | Carbonated str -> Carbonated str | Uncarbonated n -> f n

Page 124: The Power of Composition

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

MAKING LOOPS

COMPOSABLE

Page 126: The Power of Composition

Another composition problem

List of

numbers FizzBizz for one number

Page 127: The Power of Composition

Solution: the "map" transformer

List input List output FizzBizz for lists

FizzBizz for one number

List.map

Page 128: The Power of Composition

// 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

THE M-WORD

Page 130: The Power of Composition

Is there a general solution to

handling functions like this?

Page 131: The Power of Composition

Yes! “Bind” is the answer!

Bind all the things!

Page 132: The Power of Composition

Two-track input Two-track output

One-track input Two-track output

Page 133: The Power of Composition

Two-track input Two-track output

Page 134: The Power of Composition

Two-track input Two-track output

Page 135: The Power of Composition

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

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

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

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

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

Example:

Using bind to chain tasks

Page 141: The Power of Composition

When task completes Wait Wait

a.k.a "promise", "future"

Page 142: The Power of Composition

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

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

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

Example: Composing error-generating functions

Page 146: The Power of Composition

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

Validate

Generates a possible error

Page 148: The Power of Composition

Validate Canonicalize

Generates a possible error Always succeeds

Page 149: The Power of Composition

Validate Canonicalize DbFetch

Generates a possible error Generates a possible error Always succeeds

Page 150: The Power of Composition

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

map

Converting everything to two-track

Page 152: The Power of Composition

bind

map

Converting everything to two-track

Page 153: The Power of Composition

bind

map

tee map

Converting everything to two-track

Page 154: The Power of Composition

Validate Canonicalize DbFetch DbUpdate

Now we *can* compose them easily!

map bind tee, then map

Page 155: The Power of Composition

KLEISLI COMPOSITION:

WEB SERVICE

Page 156: The Power of Composition

= +

Result is same kind of thing

Kleisli Composition

Page 157: The Power of Composition

Async<HttpContext option> HttpContext

A "WebPart" (suave.io library)

See suave.io site for more

Page 158: The Power of Composition

= >=>

Result is another WebPart so you can repeat

WebPart Composition

Kleisli composition symbol

Page 159: The Power of Composition

path "/hello" >=> OK "Hello" // a WebPart

Checks request path (might fail)

Sets response

Page 160: The Power of Composition

choose [ path "/hello" >=> OK "Hello" path "/goodbye" >=> OK "Goodbye" ]

Picks first WebPart that succeeds

Page 161: The Power of Composition

GET >=> choose [ path "/hello" >=> OK "Hello" path "/goodbye" >=> OK "Goodbye" ]

Only succeeds if request is a GET

Page 162: The Power of Composition

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

Http

Response Http

Request

As I promised – no classes, no loops, etc!

Page 164: The Power of Composition

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

Slides and video here

fsharpforfunandprofit.com/composition

Thank you!

"Domain modelling Made Functional" book

fsharpforfunandprofit.com/books

@ScottWlaschin Me on twitter

fsharpforfunandprofit.com/videos