SlideShare une entreprise Scribd logo
1  sur  261
Télécharger pour lire hors ligne
The
Functional Programming
Toolkit
(NDC Oslo 2019)
@ScottWlaschin
fsharpforfunandprofit.com
Why do functional programmers
use so many strange words?
Functional programming is scary
Functional programming is scary
Functional programming is scary
Object oriented programming is scary
These aren't just academic concepts.
They are actually useful tools!
Functional programmers have a
standard set of tools
map
traverse
bind
return
lift
The Functional Toolkit
• Composition
• Combination/Aggregation
• Iteration
• Working with effects
– Mixing effects and non-effects
– Chaining effects in series
– Working with effects in parallel
– Pulling effects out of a list
The Functional Toolkit
• Composition: compose
• Iteration: fold
• Combination/Aggregation: combine & reduce
• Working with effects
– Mixing effects and non-effects: map & return
– Chaining effects in series: bind/flatMap
– Working with effects in parallel: apply, lift, zip
– Pulling effects out of a list: sequence, traverse
FunctionalToolkit (FP jargon version)
• Combination/Aggregation: Monoid
• Working with effects
– Mixing effects and non-effects: Functor
– Chaining effects in series: Monad
– Working with effects in parallel: Applicative
FunctionalToolkit (FP jargon version)
• Combination/Aggregation: Monoid
• Working with effects
– Mixing effects and non-effects: Functor
– Chaining effects in series: Monad
– Working with effects in parallel: Applicative
This talk
This talk
A whirlwind tour of many sights
Don't worry if you don't understand everything
What I'll talk about
• The core principles of FP
• Function transformers
• Some tools in the functional toolkit
– map
– bind
– lift
• An example of using all the tools together
Core principles of
statically-typed FP
Part I
Core principles of (statically-typed) FP
Function
Functions are things
Composition everywhere
Core FP principle:
Functions are things
Function
The Tunnel of
Transformation
Function
apple -> banana
A function is a thing which
transforms inputs to outputs
A function is a standalone thing,
not attached to a class
It can be used for inputs and outputs
of other functions
input
A function can be an output
A function can be an output
output
A function can be an input
A function can be an input
input output
A function can be a parameter
A function can be a parameter
You can build very complex systems
from this simple foundation!
Most of the tools in the functional toolkit are "function
transformers" that convert functions to functions
Core FP principle:
Composition everywhere
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
The Lego philosophy let's you make big things!
Can we apply these ideas to
programming?
Functional Programming Philosophy
• Design functions that do one thing well
– Functions can be reused in different contexts
• Design functions to work together
– Expect the output of every function to become
the input to another, as yet unknown,function
• Use types to ensure that inputs match outputs
Function composition
Function 1
apple -> banana
Function 2
banana -> cherry
>>
Function 1
apple -> banana
Function 2
banana -> cherry
New Function
apple -> cherry
Can't tell it was built from
smaller functions!
Where did the banana go?
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
A web application built from
functions only (no classes!)
Http
Response
Http
Request
I have a whole talk on "The Power of Composition" at
fsharpforfunandprofit.com/composition
A web application built from
functions only (no classes!)
Composition example in F#
let add1 x = x + 1
let double x = x + x
Introducing F#
let add1 x = x + 1
let double x = x + x
let square = fun x -> x * x
Introducing F#
add1 5 // = 6
double (add1 5) // = 12
square (double (add1 5)) // = 144
How to compose functions together
add1 double square5 6 12 144
5 |> add1 // = 6
5 |> add1 |> double // = 12
5 |> add1 |> double |> square // = 144
Piping in F#
Problems with composition
Composition works well when
the types match up


Composition doesn't work well
when the types don't match up
Fix: Insert a converter function
into the pipeline
Converter
function
5 |> add1 |> strLen
// ^ error: expecting an int
5 |> add1 |> intToStr |> strLen
// ^ fixed!
F# example

What if the types match up but
they're wrapped in something?
Option< >

What if the types match up but
they're wrapped in something?
List< >
FunctionTransformers
Part II
FunctionTransformers
Part II
What do railways
have to do with
programming?
Receive request
Validate request
Lowercase the email
Update user record in DB
Return result to user
type Request = {
name: string;
email: string }
"As a user I want to update my name and email address"
string UpdateCustomer()
{
var request = receiveRequest();
validateRequest(request);
lowercaseEmail(request);
db.updateDbFromRequest(request);
return "OK";
}
string UpdateCustomerWithErrorHandling()
{
var request = receiveRequest();
var isValidated = validateRequest(request);
if (!isValidated) {
return "Request is not valid"
}
lowercaseEmail(request);
db.updateDbFromRequest(request);
smtpServer.sendEmail(request.Email)
return "OK";
}
string UpdateCustomerWithErrorHandling()
{
var request = receiveRequest();
var isValidated = validateRequest(request);
if (!isValidated) {
return "Request is not valid"
}
lowercaseEmail(request);
var result = db.updateDbFromRequest(request);
if (!result) {
return "Customer record not found"
}
return "OK";
}
string UpdateCustomerWithErrorHandling()
{
var request = receiveRequest();
var isValidated = validateRequest(request);
if (!isValidated) {
return "Request is not valid"
}
lowercaseEmail(request);
try {
var result = db.updateDbFromRequest(request);
if (!result) {
return "Customer record not found"
}
} catch {
return "DB error: Customer record not updated"
}
return "OK";
}
string UpdateCustomerWithErrorHandling()
{
var request = receiveRequest();
var isValidated = validateRequest(request);
if (!isValidated) {
return "Request is not valid"
}
lowercaseEmail(request);
try {
var result = db.updateDbFromRequest(request);
if (!result) {
return "Customer record not found"
}
} catch {
return "DB error: Customer record not updated"
}
return "OK";
}
Use a Result type
for error handling
Request SuccessValidate
Failure
type Result =
| Ok of SuccessValue
| Error of ErrorValue
A choice type, aka sum type
Request SuccessValidate
Failure
let validateInput input =
if input.name = "" then
Error "Name must not be blank"
else if input.email = "" then
Error "Email must not be blank"
else
Ok input // happy path
validateInput
Step 1 Step 2 Step 3
Step 1 Step 2 Step 3
Functional flow without error handling
let updateCustomer =
receiveRequest()
|> validateRequest
|> lowercaseEmail
|> updateDbFromRequest
|> returnMessage
Before
One track
let updateCustomerWithErrorHandling =
receiveRequest()
|> validateRequest
|> lowercaseEmail
|> updateDbFromRequest
|> returnMessage
Functional flow with error handling
After
Two track
How to implement
Railway Oriented Programming
Success!
Failure
Input ->
Validate UpdateDbon success
bypass
Validate UpdateDb
How to compose
these functions?
Step 1 Step 2 Step 3
>> >>
Composing one-track functions is fine...
Step 1 Step 2 Step 3
>> >>
... and composing two-track functions is fine...
Step 1 Step 2 Step 3
 
... but composing switches is not allowed!
How to combine the
mismatched functions?
“Bind” is the answer!
Bind all the things!
Two-track input Two-track output
One-track input Two-track output


Two-track input
Slot for switch function
Two-track output
Two-track input Two-track output
let bind nextFunction twoTrackInput =
match twoTrackInput with
| Ok success -> nextFunction success
| Error err -> Error err
Two-track input Two-track output
let bind nextFunction twoTrackInput =
match twoTrackInput with
| Ok success -> nextFunction success
| Error err -> Error err
Two-track input Two-track output
let bind nextFunction twoTrackInput =
match twoTrackInput with
| Ok success -> nextFunction success
| Error err -> Error err
Two-track input Two-track output
©
let bind nextFunction twoTrackInput =
match twoTrackInput with
| Ok success -> nextFunction success
| Error err -> Error err
Two-track input Two-track output
Composing switches - review
Step 1 Step 2 Step 3
Step 1 Step 2 Step 3
Validation using Bind
Validating input
type Input = {
Name : string
Email : string
}
nameLessThan50
let nameNotBlank input =
if input.Name = "" then
Error "Name must not be blank"
else Ok input
Let nameLessThan50 input =
if input.Name.Length > 50 then
Error "Name must not be longer than 50 chars"
else Ok input
Let emailNotBlank input =
if input.Email = "" then
Error "Email must not be blank"
else Ok input
nameNotBlank
emailNotBlank
nameNotBlank (composed with)
nameLessThan50 (composed with)
emailNotBlank
nameNotBlank nameLessThan50 emailNotBlank
nameLessThan50 emailNotBlanknameNotBlank
nameNotBlank
bind nameLessThan50
bind emailNotBlank
request
|> nameNotBlank
|> Result.bind nameLessThan50
|> Result.bind emailNotBlank
name50 emailNotBlanknameNotBlank
validateInput
let validateInput input =
input
|> nameNotBlank
|> Result.bind nameLessThan50
|> Result.bind emailNotBlank
validateInput
Shapes vs.Types
FunctionB
Result<'TEntity,string>
FunctionA
Correct shape AND types match
Correct shape, but types don't match
How do single track functions
fit this model?
// trim spaces and lowercase
let lowercaseEmail input =
{input with
email = input.email.Trim().ToLower() }
lowercaseEmail
Won't compose!
UpdateDb EtcValidate
LowercaseEmail
Two-track input
Slot for one-track function
Two-track output
Two-track input Two-track output
lowercaseEmaillowercaseEmail
Two-track input Two-track output
let map singleTrackFunction twoTrackInput =
match twoTrackInput with
| Ok s -> Ok (singleTrackFunction s)
| Error e -> Error e
let map singleTrackFunction twoTrackInput =
match twoTrackInput with
| Ok s -> Ok (singleTrackFunction s)
| Error e -> Error e
Two-track input Two-track output
let map singleTrackFunction twoTrackInput =
match twoTrackInput with
| Ok s -> Ok (singleTrackFunction s)
| Error e -> Error e
Two-track input Two-track output
let map singleTrackFunction twoTrackInput =
match twoTrackInput with
| Ok s -> Ok (singleTrackFunction s)
| Error e -> Error e
Two-track input Two-track output
let map singleTrackFunction twoTrackInput =
match twoTrackInput with
| Ok s -> Ok (singleTrackFunction s)
| Error e -> Error e
Two-track input Two-track output
let map singleTrackFunction twoTrackInput =
match twoTrackInput with
| Ok s -> Ok (singleTrackFunction s)
| Error e -> Error e
Two-track input Two-track output
Converting one-track functions
UpdateDb EtcValidate
LowercaseEmail
Will compose
map
Converting everything to two-track
bind
map
Converting everything to two-track
These are "function
transformers"!
Validate LowercaseEmail DbUpdate
Using function transformers so that *can*
compose different shaped functions
map bind
Understanding "effects"
Part III
What is an effect?
• A collection type
List<_>
• A type enhanced with extra data
Option<_>, Result<_>
• A type that interacts with the outside world
Async<_>, Task<_>, Random<_>
• A type that carries state
State<_>, Parser<_>
What is an effect?
• A collection type
List<_>
• A type enhanced with extra data
Option<_>, Result<_>
• A type that interacts with the outside world
Async<_>, Task<_>, Random<_>
• A type that carries state
State<_>, Parser<_>
We'll focus on
three for this talk
"Normal" world vs.
"Effects" world
"Normal" world
int
string
bool
int -> string
int -> bool
"Option" world
Option<int>
Option<string>
Option<bool>
Option<int> -> Option<string>
Option<int> -> Option<bool>
"List" world
List<int>
List<string>
List<bool>
List<int> -> List<string>
List<int> -> List<bool>
"Async" world
Async<int>
Async<string>
Async<bool>
Async<int> -> Async<string>
Async<int> -> Async<bool>
Generic "Effects" world
E<int>
E<string>
E<bool>
E<int> -> E<string>
E<int> -> E<bool>
Different names, same concept
• "Effect" world
• "Enhanced" world
• "Elevated" world
– Because we use the word "lift" a lot!
How to work with effects?
Challenge:
Example scenario
• Download a URL into a JSON object
• Decode the JSON into a Customer DTO
• Convert the DTO into a valid Customer
• Store the Customer in a database
NormalWorld
Result World
AsyncWorld
Url
AsyncResult<Json,Err>
Download the json file
World of normal values
Result World
R<CustomerDto,Err>
Json
Decode the JSON into a DTO
World of normal values
Result World
R<name> R<email>
CustomerDto
Validate the fields of the customer
World of normal values
validName validEmail
validCustomer
Construct a customer from the fields
NormalWorld
Result World
AsyncWorld
Customer
AsyncResult<unit,Err>
Store the customer in the DB
How do we compose these
functions together?
None the worlds match up ...
... but we can use the functional toolkit!
Example:
Working with Options
World of normal values
int string bool
World of options
Option<int> Option<string> Option<bool>
World of options
World of normal values
int string bool
Option<int> Option<string> Option<bool>

World of options
World of normal values
Option<int> Option<string> Option<bool>

int string bool
add1 1 // 2
add1 (Some 1) // error
let add1ToOption opt =
if opt.IsSome then
let newVal = add1 opt.Value
Some newVal
else
None 
World of options
World of normal values
add1 
World of options
World of normal values
add1
Moving functions between
worlds with "map"
Tool #1
let add1ToOption opt =
if opt.IsSome then
Some (add1 opt.Value)
else
None
Let's take this code and turn it
into a generic, reusable tool
let optionMap f opt =
if opt.IsSome then
Some (f opt.Value)
else
None
let optionMap f =
fun opt ->
if opt.IsSome then
Some (f opt.Value)
else
None
let optionMap f
fun opt ->
if opt.IsSome then
Some (f opt.Value)
else
None
World of options
World of normal values
Option<T> -> -> Option<U>
optionMap
T -> -> U
let add1 x = ...
(optionMap add1) (Some 1)

Example:
Working with List world
let add1ToEach aList =
let newList = new List()
for item in aList do
let newItem = add1 item
newList.Add(newItem)
// return
newList

World of lists
World of normal values
add1 
let listMap f aList =
let newList = new List()
for item in aList do
let newItem = f item
newList.Add(newItem)
// return
newList
Let's make a generic, reusable
tool again
let listMap f aList =
let newList = new List()
for item in aList do
let newItem = f item
newList.Add(newItem)
// return
newList
let listMap f =
fun aList ->
let newList = new List()
for item in aList do
let newItem = f item
newList.Add(newItem)
// return
newList
World of lists
World of normal values
listMap
List<T> -> -> List<U>
T -> -> U
let add1 x = ...
(listMap add1) [1;2;3]
Q: Why is this any better than writing
your own loops every time?
A: Because it's a pattern you
can learn to recognize.
World of async
World of normal values
async<T> -> -> async<U>
asyncMap
T -> -> U
We do the same for other worlds too
Guideline:
Most wrapped generic types
have a “map”. Use it!
Guideline:
If you create your own generic type,
create a “map” for it.
FP terminology
A functor is
i. An effect type
– e.g. Option<>, List<>, Async<>
ii. Plus a "map" function that "lifts" a function to
the effects world
– a.k.a. select, lift
iii. And it must have a sensible implementation
– the Functor laws
Moving values between worlds
with "return"
Tool #2
World of options
World of normal values
Option<int>
Option.return
int
let x = 42
let intOption = Some x
World of lists
World of normal values
List<int>
List.return
int
let x = 42
let intList = [x]
Chaining world-crossing
functions with "bind"
Tool #3
What's a
world-crossing function?
let range max = [1..max]
// int -> List<int>
ListWorld
Normal world
A world crossing function
List<int>
int
range
let getCustomer id =
if customerFound then
Some customerData
else
None
// CustomerId -> Option<CustomerData>
OptionWorld
Normal world
A world crossing function
Option<CustomerData>
CustomerId
getCustomer
Problem:
How do you chain
world-crossing functions?
let optionExample input =
let x = doSomething input
if x.IsSome then
let y = doSomethingElse (x.Value)
if y.IsSome then
let z = doAThirdThing (y.Value)
if z.IsSome then
let result = z.Value
Some result
else
None
else
None
else
None
let taskExample input =
let taskX = startTask input
taskX.WhenFinished (fun x ->
let taskY = startAnotherTask x
taskY.WhenFinished (fun y ->
let taskZ = startThirdTask y
taskZ.WhenFinished (fun z ->
z // final result
)
)
)
How can we fix this?
let optionExample input =
let x = doSomething input
if x.IsSome then
let y = doSomethingElse (x.Value)
if y.IsSome then
let z = doAThirdThing (y.Value)
if z.IsSome then
// do something with z.Value
// in this block
else
None
else
None
else
None
Let's fix this!
There is a pattern we can exploit...
let optionExample input =
let x = doSomething input
if x.IsSome then
let y = doSomethingElse (x.Value)
if y.IsSome then
let z = doAThirdThing (y.Value)
if z.IsSome then
// do something with z.Value
// in this block
else
None
else
None
else
None
let optionExample input =
let x = doSomething input
if x.IsSome then
let y = doSomethingElse (x.Value)
if y.IsSome then
// do something with y.Value
// in this block
else
None
else
None
let optionExample input =
let x = doSomething input
if x.IsSome then
// do something with x.Value
// in this block
else
None
Can you see the pattern?
if opt.IsSome then
//do something with opt.Value
else
None
let ifSomeDo f opt =
if opt.IsSome then
f opt.Value
else
None
let example input =
doSomething input
|> ifSomeDo doSomethingElse
|> ifSomeDo doAThirdThing
|> ifSomeDo ...
let ifSomeDo f opt =
if opt.IsSome then
f opt.Value
else
None
Some
None
Input ->
Let's revisit the railway analogy
on Some
Bypass on None
“Bind” is the answer (again!)
Option input Option output
One-track input Option output


Option input
Slot for switch function
Option output
Option input Option output
let bind nextFunction optionInput =
match optionInput with
| Some s -> nextFunction s
| None -> None
Option input Option output
let bind nextFunction optionInput =
match optionInput with
| Some s -> nextFunction s
| None -> None
Option input Option output
let bind nextFunction optionInput =
match optionInput with
| Some s -> nextFunction s
| None -> None
Option input Option output
let bind nextFunction optionInput =
match optionInput with
| Some s -> nextFunction s
| None -> None
Option input Option output
Pattern:
Use "bind" to chain options
let optionExample input =
let x = doSomething input
if x.IsSome then
let y = doSomethingElse (x.Value)
if y.IsSome then
let z = doAThirdThing (y.Value)
if z.IsSome then
let result = z.Value
Some result
else
None
else
None
else
None
Before
let optionBind f opt =
match opt with
| Some v -> f v
| None -> None
After
let optionExample input =
doSomething input
|> optionBind doSomethingElse
|> optionBind doAThirdThing
|> optionBind ...
let optionBind f opt =
match opt with
| Some v -> f v
| None -> None
No pyramids!
Code is linear and clear.
After
Pattern:
Use "bind" to chain tasks
a.k.a "promise" "future"
When task
completesWait Wait
let taskExample input =
let taskX = startTask input
taskX.WhenFinished (fun x ->
let taskY = startAnotherTask x
taskY.WhenFinished (fun y ->
let taskZ = startThirdTask y
taskZ.WhenFinished (fun z ->
z // final result
)
)
)
Before
let taskBind f task =
task.WhenFinished (fun taskResult ->
f taskResult)
let taskExample input =
startTask input
|> taskBind startAnotherTask
|> taskBind startThirdTask
|> taskBind ...
After
Why is bind so important?
It makes world-crossing functions
composable
EffectsWorld
Normal World
a
E<b>
Before bind:
A diagonal function
(world crossing)
bind
bind
EffectsWorld
Normal World
a
E<b>
EffectsWorld
Normal World
E<a> E<b>
After bind:
A horizontal function
(all in E-world)
bind
EffectsWorld
Normal World
a
E<b>
EffectsWorld
Normal World
E<a> E<b>
NormalWorld
Effects World
"Diagonal" functions can't be composed
NormalWorld
Effects World
Bind
NormalWorld
Effects World
Bind
NormalWorld
Effects World
Bind
NormalWorld
Effects World
"Horizontal" functions can be composed
FP terminology
A monad is
i. An effect type
– e.g. Option<>, List<>, Async<>
ii. Plus a return function
– a.k.a. pure unit
iii. Plus a bind function that converts a "diagonal"
(world-crossing) function into a "horizontal" (E-
world-only) function
– a.k.a. >>= flatMap SelectMany
iv. And bind/return must have sensible implementations
– the Monad laws
TLDR: If you want to chain effects-
generating functions in series,
use a Monad
Combining effects in parallel
with applicatives
Tool #4
How to combine effects?
Option<T> Option<U>+
Option<T,U>
Some 42 Some "hello"+
Some (42,"hello")
Combining options
This is what you expect!
Some 42 None+
None
Combining options
How to combine Lists?
List<T> List<U>+
List<T,U>
[1,2,3] ["a","b","c"]+
[ (1,"a"), (1,"b"), (1,"c")
(2,"a"), (2,"b"), (2,"c")
(3,"a"), (3,"b"), (3,"c") ]
Combining lists (cross product)
[1,2,3] ["a","b","c"]+
[ (1,"a")
(2,"b")
(3,"c") ]
Combining lists (zip)
The general term for this is
"applicative functor"
Option, List, Async are all applicatives
FP terminology
A applicative (functor) is
i. An effect type
– e.g. Option<>, List<>, Async<>
ii. Plus a return function
– a.k.a. pure unit
iii. Plus a function that combines two effects into one
– a.k.a. <*> apply pair liftA2
iv. And apply/return must have sensible implementations
– the Applicative Functor laws
So why is this useful?
Problem:
How to validate multiple fields
in parallel?
type Customer = {
Name : String50
Email : EmailAddress
Birthdate : Date
}
validateName validateEmail validateBirthdate
So we create some validation functions:
Each field must be validated
validateName validateEmail validateBirthdate
Problem: Validation done in series.
So only one error at a time is returned
type CustomerDto = {
name : string
email : string
birthdate : string
} validateName
validateEmail
validateBirthdate
Combine
output
Now we do get all
errors at once!
... But how to
combine them?
World of normal values
Result World
R<name> R<email> R<bdate>
validName validEmail validDate
World of normal values
validCustomer
We know how to combine the normal values
(use a constructor)
Result World
R<name> R<email> R<bdate>
R<Customer>
The output is also in
Result world
Use the magic
of Applicatives!
Introducing "liftA2", "liftA3", etc
ResultWorld
NormalWorld
Option<T>, Option<U> -> -> Option<V>
liftA2
T,U -> -> V
"liftA2" is just like map but works
on functions with two parameters
ResultWorld
NormalWorld
Opt<T>,Opt<U>,Opt<V> -> -> Option<W>
liftA3
T,U,V -> -> W
"liftA3" is just like map but works
on functions with three parameters
let dtoToCustomer (dto:CustomerDto) =
// get the validated values
let nameOrError = validateName dto.name
let emailOrError = validateEmail dto.email
let birthdateOrError =
validateBirthdate dto.birthdate
// call the constructor
(liftA3 makeCustomer)
nameOrError
emailOrError
birthdateOrError
// final output is Result<Customer,ErrMsg list>
Here's where the
magic happens!
What the code looks like
Let's review the tools
The FunctionalToolbox
• "map"
– Lifts functions into an effects world
• "return"
– Lifts values into an effects world
• "bind"
– Converts "diagonal" functions into "horizontal" ones so
they can be composed.
• "apply"
– Combines two effects in parallel
– "liftA2", "liftA3" for example
Using all the tools together
Part IV
Revisiting the example scenario
• Download a URL into a JSON object
• Decode the JSON into a Customer DTO
• Convert the DTO into a valid Customer
• Store the Customer in a database
NormalWorld
Result World
AsyncWorld
Download the json file
Url
AsyncResult<Json>
World of normal values
Result World
R<CustomerDto>
Json
Decode the json
World of normal values
Result World
R<name> R<email> R<bdate>
CustomerDto
Validate fields
World of normal values
Construct the customer
validName validEmail validDate
validCustomer
NormalWorld
Result World
AsyncWorld
Customer
Store the customer in the DB
AsyncResult<unit>
We now have the tools to compose
these functions together!
World of normal values
ResultWorld
R<name> R<email> R<bdate>
CustomerDto
Validate fields AND create a customer
Use Result type for validation
R<Customer>
Use "lift3"
World of normal values
Result World
CustomerDto
R<Customer>
Validate fields AND create a customer
We now have a world crossing function from
the DTO to the Customer
World of normal values
Result World
CustomerDto
R<Customer>
Parse json AND create a customer
R<CustomerDto>
Json
Use "bind" to turn the diagonal
functions into horizontal ones
Bind Bind
World of normal values
Result World
R<Customer>
Parse json AND create a customer
R<CustomerDto>R<Json>
Bind Bind
World of normal values
Result World
Parse json AND create a customer
R<Customer>R<Json>
Then compose them into one function
let jsonToCustomer jsonOrError =
jsonOrError
|> Result.bind jsonToCustomerDto
|> Result.bind dtoToCustomer
What the code looks like
It takes much more time to explain
than to write it!
NormalWorld
Result World
AsyncWorld
Parse json AND create a customer
R<Customer>R<Json>
Then lift it up to Async
world using map
Map
NormalWorld
Result World
AsyncWorld
Parse json AND create a customer
AsyncResult<Customer>AsyncResult<Json>
NormalWorld
AsyncWorld
Customer
Store the customer in the DB
Use "bind" to turn the
diagonal function horizontal
AsyncResult<unit>
Bind
NormalWorld
Result World
AsyncWorld
AsyncResult<Customer> AsyncResult<unit>
Store the customer in the DB
Bind
NormalWorld
AsyncWorld
All steps are now composable
Url
AsyncResult<Json>
AsyncResult<Customer>AsyncResult<Json>
AsyncResult<Customer> AsyncResult<unit>
Convert JSON to customer
Store customer in DB
NormalWorld
AsyncWorld
All steps are now composable
Url
AsyncResult<Json> AsyncResult<Customer> AsyncResult<unit>
NormalWorld
AsyncWorld
All steps are now composable into one single function
Url
AsyncResult<unit>
let jsonToCustomer jsonOrError =
jsonOrError
|> Result.bind jsonToCustomerDto
|> Result.bind dtoToCustomer
let downloadAndStoreCustomer url =
url
|> downloadFile
|> Async.map jsonToCustomer
|> AsyncResult.bind storeCustomerInDb
What the code looks like
The patterns might be unfamiliar but once you get
use to them, you can compose code quickly.
Again, it takes much more time to explain than to write it!
Language support for monads
• F# has computation expressions
• Haskell has "do" notation
• Scala has "for" comprehensions
• C# has "SelectMany" 
a.k.a. using "bind" everywhere gets ugly
In conclusion…
• FP jargon is not that scary
– Can you see why monads are useful?
• The FP toolkit is very generic
– FP's use these core functions constantly!
• You can now recognize "map", "lift" and "bind"
– Don’t expect to understand them all straight away.
"The Functional ProgrammingToolkit"
– Slides and video will be posted at
• fsharpforfunandprofit.com/fptoolkit
Related talks
– "Functional Design Patterns"
• fsharpforfunandprofit.com/fppatterns
– "The Power of Composition"
• fsharpforfunandprofit.com/composition
– "Domain Modeling Made Functional"
• fsharpforfunandprofit.com/ddd
Thanks!
Twitter:@ScottWlaschin

Contenu connexe

Tendances

Pipeline oriented programming
Pipeline oriented programmingPipeline oriented programming
Pipeline oriented programmingScott Wlaschin
 
Domain Driven Design with the F# type System -- F#unctional Londoners 2014
Domain Driven Design with the F# type System -- F#unctional Londoners 2014Domain Driven Design with the F# type System -- F#unctional Londoners 2014
Domain Driven Design with the F# type System -- F#unctional Londoners 2014Scott Wlaschin
 
Functional Programming in JavaScript by Luis Atencio
Functional Programming in JavaScript by Luis AtencioFunctional Programming in JavaScript by Luis Atencio
Functional Programming in JavaScript by Luis AtencioLuis Atencio
 
Functional Programming Patterns (NDC London 2014)
Functional Programming Patterns (NDC London 2014)Functional Programming Patterns (NDC London 2014)
Functional Programming Patterns (NDC London 2014)Scott Wlaschin
 
Domain Modeling with FP (DDD Europe 2020)
Domain Modeling with FP (DDD Europe 2020)Domain Modeling with FP (DDD Europe 2020)
Domain Modeling with FP (DDD Europe 2020)Scott Wlaschin
 
Dr Frankenfunctor and the Monadster
Dr Frankenfunctor and the MonadsterDr Frankenfunctor and the Monadster
Dr Frankenfunctor and the MonadsterScott Wlaschin
 
Enterprise Tic-Tac-Toe
Enterprise Tic-Tac-ToeEnterprise Tic-Tac-Toe
Enterprise Tic-Tac-ToeScott Wlaschin
 
Sum and Product Types - The Fruit Salad & Fruit Snack Example - From F# to Ha...
Sum and Product Types -The Fruit Salad & Fruit Snack Example - From F# to Ha...Sum and Product Types -The Fruit Salad & Fruit Snack Example - From F# to Ha...
Sum and Product Types - The Fruit Salad & Fruit Snack Example - From F# to Ha...Philip Schwarz
 
Functional Programming Patterns (BuildStuff '14)
Functional Programming Patterns (BuildStuff '14)Functional Programming Patterns (BuildStuff '14)
Functional Programming Patterns (BuildStuff '14)Scott Wlaschin
 
Clean Pragmatic Architecture - Avoiding a Monolith
Clean Pragmatic Architecture - Avoiding a MonolithClean Pragmatic Architecture - Avoiding a Monolith
Clean Pragmatic Architecture - Avoiding a MonolithVictor Rentea
 
Domain Modeling Made Functional (KanDDDinsky 2019)
Domain Modeling Made Functional (KanDDDinsky 2019)Domain Modeling Made Functional (KanDDDinsky 2019)
Domain Modeling Made Functional (KanDDDinsky 2019)Scott Wlaschin
 
Designing with Capabilities
Designing with CapabilitiesDesigning with Capabilities
Designing with CapabilitiesScott Wlaschin
 
Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patter...
Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patter...Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patter...
Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patter...Domenic Denicola
 
7 rules of simple and maintainable code
7 rules of simple and maintainable code7 rules of simple and maintainable code
7 rules of simple and maintainable codeGeshan Manandhar
 
You code sucks, let's fix it
You code sucks, let's fix itYou code sucks, let's fix it
You code sucks, let's fix itRafael Dohms
 
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
 
Clean code and Code Smells
Clean code and Code SmellsClean code and Code Smells
Clean code and Code SmellsMario Sangiorgio
 

Tendances (20)

Pipeline oriented programming
Pipeline oriented programmingPipeline oriented programming
Pipeline oriented programming
 
Domain Driven Design with the F# type System -- F#unctional Londoners 2014
Domain Driven Design with the F# type System -- F#unctional Londoners 2014Domain Driven Design with the F# type System -- F#unctional Londoners 2014
Domain Driven Design with the F# type System -- F#unctional Londoners 2014
 
Functional Programming in JavaScript by Luis Atencio
Functional Programming in JavaScript by Luis AtencioFunctional Programming in JavaScript by Luis Atencio
Functional Programming in JavaScript by Luis Atencio
 
Functional Programming Patterns (NDC London 2014)
Functional Programming Patterns (NDC London 2014)Functional Programming Patterns (NDC London 2014)
Functional Programming Patterns (NDC London 2014)
 
Domain Modeling with FP (DDD Europe 2020)
Domain Modeling with FP (DDD Europe 2020)Domain Modeling with FP (DDD Europe 2020)
Domain Modeling with FP (DDD Europe 2020)
 
Dr Frankenfunctor and the Monadster
Dr Frankenfunctor and the MonadsterDr Frankenfunctor and the Monadster
Dr Frankenfunctor and the Monadster
 
Enterprise Tic-Tac-Toe
Enterprise Tic-Tac-ToeEnterprise Tic-Tac-Toe
Enterprise Tic-Tac-Toe
 
Sum and Product Types - The Fruit Salad & Fruit Snack Example - From F# to Ha...
Sum and Product Types -The Fruit Salad & Fruit Snack Example - From F# to Ha...Sum and Product Types -The Fruit Salad & Fruit Snack Example - From F# to Ha...
Sum and Product Types - The Fruit Salad & Fruit Snack Example - From F# to Ha...
 
Functional Programming Patterns (BuildStuff '14)
Functional Programming Patterns (BuildStuff '14)Functional Programming Patterns (BuildStuff '14)
Functional Programming Patterns (BuildStuff '14)
 
Clean Pragmatic Architecture - Avoiding a Monolith
Clean Pragmatic Architecture - Avoiding a MonolithClean Pragmatic Architecture - Avoiding a Monolith
Clean Pragmatic Architecture - Avoiding a Monolith
 
Domain Modeling Made Functional (KanDDDinsky 2019)
Domain Modeling Made Functional (KanDDDinsky 2019)Domain Modeling Made Functional (KanDDDinsky 2019)
Domain Modeling Made Functional (KanDDDinsky 2019)
 
Designing with Capabilities
Designing with CapabilitiesDesigning with Capabilities
Designing with Capabilities
 
Clean code
Clean codeClean code
Clean code
 
Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patter...
Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patter...Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patter...
Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patter...
 
7 rules of simple and maintainable code
7 rules of simple and maintainable code7 rules of simple and maintainable code
7 rules of simple and maintainable code
 
You code sucks, let's fix it
You code sucks, let's fix itYou code sucks, let's fix it
You code sucks, let's fix it
 
Clean code slide
Clean code slideClean code slide
Clean code slide
 
Redux Thunk
Redux ThunkRedux Thunk
Redux Thunk
 
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...
 
Clean code and Code Smells
Clean code and Code SmellsClean code and Code Smells
Clean code and Code Smells
 

Similaire à The Functional Programming Toolkit (NDC Oslo 2019)

Incredible Machine with Pipelines and Generators
Incredible Machine with Pipelines and GeneratorsIncredible Machine with Pipelines and Generators
Incredible Machine with Pipelines and Generatorsdantleech
 
TPSE Thailand 2015 - Rethinking Web with React and Flux
TPSE Thailand 2015 - Rethinking Web with React and FluxTPSE Thailand 2015 - Rethinking Web with React and Flux
TPSE Thailand 2015 - Rethinking Web with React and FluxJirat Kijlerdpornpailoj
 
Generalized Functors - Realizing Command Design Pattern in C++
Generalized Functors - Realizing Command Design Pattern in C++Generalized Functors - Realizing Command Design Pattern in C++
Generalized Functors - Realizing Command Design Pattern in C++ppd1961
 
Understanding Framework Architecture using Eclipse
Understanding Framework Architecture using EclipseUnderstanding Framework Architecture using Eclipse
Understanding Framework Architecture using Eclipseanshunjain
 
Immutability and pure functions
Immutability and pure functionsImmutability and pure functions
Immutability and pure functionssparkfabrik
 
Functional Swift
Functional SwiftFunctional Swift
Functional SwiftGeison Goes
 
From object oriented to functional domain modeling
From object oriented to functional domain modelingFrom object oriented to functional domain modeling
From object oriented to functional domain modelingCodemotion
 
From object oriented to functional domain modeling
From object oriented to functional domain modelingFrom object oriented to functional domain modeling
From object oriented to functional domain modelingMario Fusco
 
ClojureScript - Making Front-End development Fun again - John Stevenson - Cod...
ClojureScript - Making Front-End development Fun again - John Stevenson - Cod...ClojureScript - Making Front-End development Fun again - John Stevenson - Cod...
ClojureScript - Making Front-End development Fun again - John Stevenson - Cod...Codemotion
 
Adding a modern twist to legacy web applications
Adding a modern twist to legacy web applicationsAdding a modern twist to legacy web applications
Adding a modern twist to legacy web applicationsJeff Durta
 
Adding a modern twist to legacy web applications
Adding a modern twist to legacy web applicationsAdding a modern twist to legacy web applications
Adding a modern twist to legacy web applicationsJeff Durta
 
How To Use IO Monads in Scala?
 How To Use IO Monads in Scala? How To Use IO Monads in Scala?
How To Use IO Monads in Scala?Knoldus Inc.
 
Introduction to ReactJS and Redux
Introduction to ReactJS and ReduxIntroduction to ReactJS and Redux
Introduction to ReactJS and ReduxBoris Dinkevich
 
O365 Saturday - Deepdive SharePoint Client Side Rendering
O365 Saturday - Deepdive SharePoint Client Side RenderingO365 Saturday - Deepdive SharePoint Client Side Rendering
O365 Saturday - Deepdive SharePoint Client Side RenderingRiwut Libinuko
 
Introduction to React for Frontend Developers
Introduction to React for Frontend DevelopersIntroduction to React for Frontend Developers
Introduction to React for Frontend DevelopersSergio Nakamura
 
WebNet Conference 2012 - Designing complex applications using html5 and knock...
WebNet Conference 2012 - Designing complex applications using html5 and knock...WebNet Conference 2012 - Designing complex applications using html5 and knock...
WebNet Conference 2012 - Designing complex applications using html5 and knock...Fabio Franzini
 

Similaire à The Functional Programming Toolkit (NDC Oslo 2019) (20)

Incredible Machine with Pipelines and Generators
Incredible Machine with Pipelines and GeneratorsIncredible Machine with Pipelines and Generators
Incredible Machine with Pipelines and Generators
 
TPSE Thailand 2015 - Rethinking Web with React and Flux
TPSE Thailand 2015 - Rethinking Web with React and FluxTPSE Thailand 2015 - Rethinking Web with React and Flux
TPSE Thailand 2015 - Rethinking Web with React and Flux
 
Generalized Functors - Realizing Command Design Pattern in C++
Generalized Functors - Realizing Command Design Pattern in C++Generalized Functors - Realizing Command Design Pattern in C++
Generalized Functors - Realizing Command Design Pattern in C++
 
Functional programming
Functional programmingFunctional programming
Functional programming
 
Understanding Framework Architecture using Eclipse
Understanding Framework Architecture using EclipseUnderstanding Framework Architecture using Eclipse
Understanding Framework Architecture using Eclipse
 
Immutability and pure functions
Immutability and pure functionsImmutability and pure functions
Immutability and pure functions
 
Functional Swift
Functional SwiftFunctional Swift
Functional Swift
 
From object oriented to functional domain modeling
From object oriented to functional domain modelingFrom object oriented to functional domain modeling
From object oriented to functional domain modeling
 
From object oriented to functional domain modeling
From object oriented to functional domain modelingFrom object oriented to functional domain modeling
From object oriented to functional domain modeling
 
ClojureScript - Making Front-End development Fun again - John Stevenson - Cod...
ClojureScript - Making Front-End development Fun again - John Stevenson - Cod...ClojureScript - Making Front-End development Fun again - John Stevenson - Cod...
ClojureScript - Making Front-End development Fun again - John Stevenson - Cod...
 
Adding a modern twist to legacy web applications
Adding a modern twist to legacy web applicationsAdding a modern twist to legacy web applications
Adding a modern twist to legacy web applications
 
Adding a modern twist to legacy web applications
Adding a modern twist to legacy web applicationsAdding a modern twist to legacy web applications
Adding a modern twist to legacy web applications
 
ES6: The Awesome Parts
ES6: The Awesome PartsES6: The Awesome Parts
ES6: The Awesome Parts
 
Function
Function Function
Function
 
How To Use IO Monads in Scala?
 How To Use IO Monads in Scala? How To Use IO Monads in Scala?
How To Use IO Monads in Scala?
 
Introduction to ReactJS and Redux
Introduction to ReactJS and ReduxIntroduction to ReactJS and Redux
Introduction to ReactJS and Redux
 
O365 Saturday - Deepdive SharePoint Client Side Rendering
O365 Saturday - Deepdive SharePoint Client Side RenderingO365 Saturday - Deepdive SharePoint Client Side Rendering
O365 Saturday - Deepdive SharePoint Client Side Rendering
 
Refactoring
RefactoringRefactoring
Refactoring
 
Introduction to React for Frontend Developers
Introduction to React for Frontend DevelopersIntroduction to React for Frontend Developers
Introduction to React for Frontend Developers
 
WebNet Conference 2012 - Designing complex applications using html5 and knock...
WebNet Conference 2012 - Designing complex applications using html5 and knock...WebNet Conference 2012 - Designing complex applications using html5 and knock...
WebNet Conference 2012 - Designing complex applications using html5 and knock...
 

Plus de Scott Wlaschin

Domain Modeling Made Functional (DevTernity 2022)
Domain Modeling Made Functional (DevTernity 2022)Domain Modeling Made Functional (DevTernity 2022)
Domain Modeling Made Functional (DevTernity 2022)Scott Wlaschin
 
Building confidence in concurrent code with a model checker: TLA+ for program...
Building confidence in concurrent code with a model checker: TLA+ for program...Building confidence in concurrent code with a model checker: TLA+ for program...
Building confidence in concurrent code with a model checker: TLA+ for program...Scott Wlaschin
 
Reinventing the Transaction Script (NDC London 2020)
Reinventing the Transaction Script (NDC London 2020)Reinventing the Transaction Script (NDC London 2020)
Reinventing the Transaction Script (NDC London 2020)Scott Wlaschin
 
Four Languages From Forty Years Ago (NewCrafts 2019)
Four Languages From Forty Years Ago (NewCrafts 2019)Four Languages From Forty Years Ago (NewCrafts 2019)
Four Languages From Forty Years Ago (NewCrafts 2019)Scott Wlaschin
 
Four Languages From Forty Years Ago
Four Languages From Forty Years AgoFour Languages From Forty Years Ago
Four Languages From Forty Years AgoScott Wlaschin
 
Designing with capabilities (DDD-EU 2017)
Designing with capabilities (DDD-EU 2017)Designing with capabilities (DDD-EU 2017)
Designing with capabilities (DDD-EU 2017)Scott Wlaschin
 
Thirteen ways of looking at a turtle
Thirteen ways of looking at a turtleThirteen ways of looking at a turtle
Thirteen ways of looking at a turtleScott Wlaschin
 
An introduction to property based testing
An introduction to property based testingAn introduction to property based testing
An introduction to property based testingScott Wlaschin
 

Plus de Scott Wlaschin (12)

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...
 
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)
 
Four Languages From Forty Years Ago (NewCrafts 2019)
Four Languages From Forty Years Ago (NewCrafts 2019)Four Languages From Forty Years Ago (NewCrafts 2019)
Four Languages From Forty Years Ago (NewCrafts 2019)
 
Four Languages From Forty Years Ago
Four Languages From Forty Years AgoFour Languages From Forty Years Ago
Four Languages From Forty Years Ago
 
F# for C# Programmers
F# for C# ProgrammersF# for C# Programmers
F# for C# Programmers
 
Designing with capabilities (DDD-EU 2017)
Designing with capabilities (DDD-EU 2017)Designing with capabilities (DDD-EU 2017)
Designing with capabilities (DDD-EU 2017)
 
Thirteen ways of looking at a turtle
Thirteen ways of looking at a turtleThirteen ways of looking at a turtle
Thirteen ways of looking at a turtle
 
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
 
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
 

Dernier

%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrainmasabamasaba
 
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...SelfMade bd
 
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-...Steffen Staab
 
Generic or specific? Making sensible software design decisions
Generic or specific? Making sensible software design decisionsGeneric or specific? Making sensible software design decisions
Generic or specific? Making sensible software design decisionsBert Jan Schrijver
 
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfonteinmasabamasaba
 
%in Durban+277-882-255-28 abortion pills for sale in Durban
%in Durban+277-882-255-28 abortion pills for sale in Durban%in Durban+277-882-255-28 abortion pills for sale in Durban
%in Durban+277-882-255-28 abortion pills for sale in Durbanmasabamasaba
 
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...masabamasaba
 
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 🔝✔️✔️Delhi Call girls
 
Unlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language ModelsUnlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language Modelsaagamshah0812
 
TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providermohitmore19
 
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...Shane Coughlan
 
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfThe Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfkalichargn70th171
 
VTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learnVTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learnAmarnathKambale
 
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 🔝✔️✔️Delhi Call girls
 
%in kempton park+277-882-255-28 abortion pills for sale in kempton park
%in kempton park+277-882-255-28 abortion pills for sale in kempton park %in kempton park+277-882-255-28 abortion pills for sale in kempton park
%in kempton park+277-882-255-28 abortion pills for sale in kempton park masabamasaba
 
AI & Machine Learning Presentation Template
AI & Machine Learning Presentation TemplateAI & Machine Learning Presentation Template
AI & Machine Learning Presentation TemplatePresentation.STUDIO
 
Define the academic and professional writing..pdf
Define the academic and professional writing..pdfDefine the academic and professional writing..pdf
Define the academic and professional writing..pdfPearlKirahMaeRagusta1
 
+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
 
Announcing Codolex 2.0 from GDK Software
Announcing Codolex 2.0 from GDK SoftwareAnnouncing Codolex 2.0 from GDK Software
Announcing Codolex 2.0 from GDK SoftwareJim McKeeth
 
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...masabamasaba
 

Dernier (20)

%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
 
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
 
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-...
 
Generic or specific? Making sensible software design decisions
Generic or specific? Making sensible software design decisionsGeneric or specific? Making sensible software design decisions
Generic or specific? Making sensible software design decisions
 
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
 
%in Durban+277-882-255-28 abortion pills for sale in Durban
%in Durban+277-882-255-28 abortion pills for sale in Durban%in Durban+277-882-255-28 abortion pills for sale in Durban
%in Durban+277-882-255-28 abortion pills for sale in Durban
 
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
 
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 🔝✔️✔️
 
Unlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language ModelsUnlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language Models
 
TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service provider
 
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
 
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfThe Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
 
VTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learnVTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learn
 
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 🔝✔️✔️
 
%in kempton park+277-882-255-28 abortion pills for sale in kempton park
%in kempton park+277-882-255-28 abortion pills for sale in kempton park %in kempton park+277-882-255-28 abortion pills for sale in kempton park
%in kempton park+277-882-255-28 abortion pills for sale in kempton park
 
AI & Machine Learning Presentation Template
AI & Machine Learning Presentation TemplateAI & Machine Learning Presentation Template
AI & Machine Learning Presentation Template
 
Define the academic and professional writing..pdf
Define the academic and professional writing..pdfDefine the academic and professional writing..pdf
Define the academic and professional writing..pdf
 
+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...
 
Announcing Codolex 2.0 from GDK Software
Announcing Codolex 2.0 from GDK SoftwareAnnouncing Codolex 2.0 from GDK Software
Announcing Codolex 2.0 from GDK Software
 
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
 

The Functional Programming Toolkit (NDC Oslo 2019)