4. A monad is a triple (T,
η,
μ) where T is an
endofunctor T:
X-‐>X and η:
I-‐>T and μ:
T
x
T-‐>T
are 2 natural transformations satisfying these laws:
• Identity law: μ(η(T))
=
T
=
μ(T(η))
• Associative law: μ(μ(T
×
T)
×
T))
=
μ(T
×
μ(T
×
T))
A monad in X is just a monoid in the category
of endofunctors of X, with product × replaced
by composition of endofunctors and unit set
by the identity endofunctor
What is a monad?
5.
6. software developer @ codiceplastico
@amelchiori
alessandro@codiceplastico.com
About me
8. let
myString
=
"original
value"
let
myString
=
"new
value”
Immutability: values, not variables!
Duplicate definition of value ‘myString’
9. let
add
x
y
=
x
+
y
add
2
2
x:int
-‐>
y:int
-‐>
int
Type inference
10. void
ProcessItems(Item[]
items,
Action<Item>
action)
{
for(int
i
=
0;
i
<
items.Length;
i++)
{
var
item
=
items[i];
action(item);
}
}
Recursion
11. let
rec
processItems
action
=
function
|
[]
-‐>
()
|
head
::
tail
-‐>
action
head;
processItems
tail
Recursion
12. let
add
x
y
=
x
+
y
x:int
-‐>
y:int
-‐>
int
Partial function application
let
add5
x
=
add
5
x:int
-‐>
int
let
value
=
add5
10
(value
=
15)
13. let
f
x
=
x
*
x
x:int
-‐>
int
let
g
x
=
-‐x/2
+
5
x:int
-‐>
int
Functions composition
let
(<<)
f
g
x
=
f
(g
x)
('b
-‐>
'c)
-‐>
('a
-‐>
'b)
-‐>
'a
-‐>
’c
let
h
x
=
f
<<
g
x:int
-‐>
int
14. let
square
x
=
x
*
x
let
add
x
y
=
x
+
y
let
toString
x
=
x.ToString()
let
complexFunction
x
=
toString
(add
5
(square
x))
Pipeline operator
let
(|>)
x
f
=
f
x
let
complexFunction
x
=
x
|>
square
|>
add
5
|>
toString
15. let
div
x
y
=
x
/
y
x:int
-‐>
y:int
-‐>
int
div
10
5
//
2
div
10
0
//
System.DivideByZeroException
Option type
let
safeDiv
x
y
=
if
y
=
0
then
None
else
Some(x/y)
x:int
-‐>
y:int
-‐>
int
option
16. let
safeDiv
x
y
=
match
y
with
|
0
-‐>
None
|
_
-‐>
Some(x/y)
Pattern matching
let
safeDiv
x
y
=
match
y
with
|
0
-‐>
None
|
1
-‐>
Some(x/y)
Incomplete pattern matches on this expression.
For example, the value '2' may indicate a case not covered by
the pattern(s)
17. type
State
=
|
On
|
Off
let
x
=
On
let
y
=
Off
Discriminated unions
18. let
div
(x,
y)
=
…
(int
*
int)
-‐
>
int
Tuples
let
div
(x,
y)
=
match
(x,
y)
with
|
(_,
0)
-‐>
None
|
(_,
_)
-‐>
Some(x/
y)
19. type
site
=
{
Title
:
string;
Url
:
string
}
Records
let
homepage
=
{
Title
=
"Google";
Url
=
"http://www.google.com"
}
let
next
=
{
homepage
with
Title
=
"NextPage"
}
21. public
class
Company
{
public
String
BusinessName
{
get;
set;
}
public
String
TaxCode
{
get;
set;
}
public
String
VatNumber
{
get;
set;
}
public
String
AssignedBank
{
get;
set;
}
public
Boolean
IsBankAuthorized
{
get;
set;
}
}
22. Value object
An immutable object, like money or a date
range, whose equality isn't based on identity
(in general equality is based on all fields
equality)
Martin Fowler
23. Value object
An immutable object, like money or a date
range, whose equality isn't based on identity
(in general equality is based on all fields
equality)
Martin Fowler
24. public
class
CompanyProfile
{
public
String
BusinessName
{
get;
private
set;
}
public
String
TaxCode
{
get;
private
set;
}
public
String
VatNumber
{
get;
private
set;
}
public
CompanyProfile(String
businessName,
String
taxCode,
String
vatNumber=null)
{
//
check
if
parameters
are
valid
BusinessName
=
businessName;
TaxCode
=
taxCode;
VatNumber
=
vatNumber;
}
}
Value object
25. public
class
CompanyProfile
{
//
same
as
before…
public
override
Boolean
Equals(Object
other)
{
var
target
=
other
as
CompanyProfile;
return
target
==
null
?
false
:
target.BusinessName
==
this.BusinessName
&&
target.TaxCode
==
this.TaxCode
&&
target.VatCode
==
this.VatCode;
}
public
override
Int32
GetHashCode()
{
//
...
}
}
Value object’s equality
26. type
CompanyProfile
=
{
BusinessName
:
string;
TaxCode
:
string;
VatNumber
:
string
}
Value object in F#
option;
let
profile
=
{
BusinessName
=
“CodicePlastico”;
TaxNumber
=
“1234567890”;
}
27. Ubiquitous Language is the concept of
defining a language (spoken and written) that
is equally used across developers and domain
experts
Ubiquitous language
28. public
class
Company
{
...
public
String
AssignedBank
{
get;
set;
}
public
Boolean
IsBankAuthorized
{
get;
set;
}
}
Ubiquitous language
29. Rule 1:
A company must have a bank to work with
Rule 2:
A company can be authorized to work with its
assigned bank
Rule 3:
A company can be not authorized to work with
its assigned bank
Business logic
31. type
Bank
=
Bank
of
string
type
UnauthorizedBank
=
UnauthorizedBank
of
Bank
type
AuthorizedBank
=
AuthorizedBank
of
Bank
type
AssignedBank
=
|
Unauthorized
of
UnauthorizedBank
|
Authorized
of
AuthorizedBank
Business logic in F#
32. type
CompanyProfile
=
{
BusinessName:
string,
TaxCode:
string,
VatCode:
string
option
}
type
Bank
=
Bank
of
string
type
UnauthorizedBank
=
UnauthorizedBank
of
Bank
type
AuthorizedBank
=
AuthorizedBank
of
Bank
type
AssignedBank
=
|
Unauthorized
of
UnauthorizedBank
|
Authorized
of
AuthorizedBank
type
Company
=
{
Profile:
CompanyProfile,
Bank:
AssignedBank
}
Ubiquitous language to the rescue
33. The central idea of specification is to
separate the statement of how to match
a candidate, from the candidate object
that it is matched against
Specification
34. type
SpecificationResult
=
|
Success
|
Failure
of
string
type
Spec<'a>
=
'a
-‐>
SpecificationResult
Specification
35. type
Category
=
|
Default
|
Premium
|
Gold
type
Customer
=
{
Name:
string;
Category:
Category;
}
Specification: our (simple) domain
type
Item
=
{
Code:
string;
Quantity:
int;
}
type
Order
=
{
Number:
string;
Customer:
Customer;
Items:
Item
list;
}
36. let
isOrderFullFilled
:
Spec<Order>
=
let
p
order
=
match
Seq.isEmpty
order.Items
with
|
true
-‐>
Failure("Items'
list
empty")
|
false
-‐>
Success
in
p
let
isGoldCustomer
:
Spec<Customer>
=
let
p
customer
=
match
customer.Category
with
|
Gold
-‐>
Success
|
_
-‐>
Failure("No-‐gold
customer")
in
p
Specification
37. let
And
(left:
Spec<'a>)
(right:
Spec<'a>)
:
Spec<'a>
=
let
p
entity
=
match
left
entity
with
|
Success
-‐>
right
entity
|
_
-‐>
Failure("And
specification
is
not
satisfied")
in
p
Specification
38. let
order
=
{
Number
=
"1234";
Customer
=
{
Name
=
"Alessandro";
Category
=
Gold};
Items
=
[
{
Code
=
"Code1";
Quantity
=
1};
{
Code
=
"Code2";
Quantity
=
2};
];
}
let
isOrderValid
=
And
isOrderFullFilled
(adapt
isGoldCustomer
(fun
order
-‐>
order.Customer))
let
isValid
=
isOrderValid
order
Specification
47.
Cart.Apply(
Cart.Apply(null,
new
CartCreated
{
CartId=1}),
new
ItemAddedToCart
{
CartId
=
1,
ItemId
=
"A"
}
)
Commands, events and…fold (step 5)
48.
Cart.Apply(
Cart.Apply(
Cart.Apply(null,
new
CartCreated
{
CartId=1}),
new
ItemAddedToCart
{
CartId
=
1,
ItemId
=
"A"
}
),
new
ItemAddedToCart
{
CartId
=
1,
ItemId
=
"B"
}
)
Commands, events and…fold (step 5)
49. Cart.Apply(
Cart.Apply(
Cart.Apply(
Cart.Apply(null,
new
CartCreated
{
CartId=1}),
new
ItemAddedToCart
{
CartId
=
1,
ItemId
=
"A"
}
),
new
ItemAddedToCart
{
CartId
=
1,
ItemId
=
"B"
}
),
new
ItemRemovedFromCart
{
CartId
=
1,
ItemId
=
"A"
}
)
Commands, events and…fold (step 5)
50. Executing a command:
type
Exec
=
(
CartState
*
Command
)
-‐>
DomainEvent
Applying an event:
type
Apply
=
(
CartState
*
DomainEvent
)
-‐>
CartState
Commands, events and…fold (step 6)
51. type
Command
=
|
Create
of
string
|
AddItem
of
int
|
RemoveItem
of
int
|
RemoveAllItems
|
Checkout
type
Event
=
|
Created
of
string
|
ItemAdded
of
int
|
ItemRemoved
of
int
|
AllItemsRemoved
|
Checkedout
Commands, events and…fold (step 7)
52. type
CartState
=
{
Name:
string;
Items:
List<int>;
Active:
bool;
}
let
apply
state
=
function
|
Created
x
-‐>
{
Cart.empty
with
Name
=
x
}
|
ItemAdded
x
-‐>
{
state
with
Items
=
List.append
state.Items
[x]
}
|
ItemRemoved
x
-‐>
{
state
with
Items
=
List.filter
(fun
i
-‐>
i
<>
x
)
state.Items
}
|
Removed
_
-‐>
{
state
with
Items
=
List.empty
}
|
Checkedout
_
-‐>
{
state
with
Active
=
false
}
Commands, events and…fold (step 8)
53. let
domainEvents
=
[
Created("cart1");
ItemAdded(1);
ItemAdded(2);
Removed;
ItemAdded(3);
Checkedout;
]
let
state
=
List.fold
apply
Cart.empty
domainEvents
Commands, events and…fold (step 9)