The document discusses how monads can be used to prevent bugs and handle side effects like missing data in code. It provides examples of using Optional to represent missing values and chaining operations with flatMap to avoid nested if-checks. Monads allow sequencing computations in a declarative way while handling problems in the data or failures transparently.
6. public static void main(String[] args) {
//take mushrooms from the baskets,
// but not more than 20 from each
List<Integer> mushrooms = new ArrayList<>(
Arrays.asList(14, 52, 31, 62, 71, 22, 34));
int sum = 0;
int i = 0;
while (i < 6) {
if (mushrooms.get(i++) > 20) {
sum = sum + 20;
} else {
sum = sum + mushrooms.get(i);
}
}
System.out.println(sum);
}
7. And there are bugsAnd there are bugsAnd there are bugs
public static void main(String[] args) {
//take mushrooms from the baskets,
// but not more than 20 from each
List<Integer> mushrooms = new ArrayList<>(
Arrays.asList(14, 52, 31, 62, 71, 22, 34));
int sum = 0;
int i = 0;
while (i < 6) {
if (mushrooms.get(i++) > 20) {
sum = sum + 20;
} else {
sum = sum + mushrooms.get(i);
}
}
System.out.println(sum);
}
8. bugs in this code have their own bugsbugs in this code have their own bugsbugs in this code have their own bugs
26. Safer languages / safer featuresSafer languages / safer featuresSafer languages / safer features
27. LAMBDASLAMBDAS
public static void main(String[] args) {
//take mushrooms from the baskets,
// but not more than 20 from each
final List<Integer> mushrooms = new ArrayList<>(
Arrays.asList(14, 52, 31, 62, 71, 22, 34));
final int sum = mushrooms.stream()
.map(m -> Math.min(m, 20))
.reduce(0, (a, b) -> a + b);
System.out.println(sum);
}
33. THIS IS ONLY THE BEGINNINGTHIS IS ONLY THE BEGINNING
34. MUTANTSMUTANTS
public static void main(String[] args) {
//take mushrooms from the baskets,
// but not more than 20 from each
final List<Integer> mushrooms = new ArrayList<>(
Arrays.asList(14, 52, 31, 62, 71, 22, 34)
);
int avg = calcAverage(mushrooms);
final int sum = mushrooms.stream()
.map(m -> Math.min(m, 20))
.reduce(0, (a, b) -> a + b);
System.out.println(sum);
}
44. public class Person {
private String firstName;
private String lastName;
private BigDecimal salary;
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public BigDecimal getSalary() {
return salary;
}
45.
46. Immutability in javaImmutability in javaImmutability in java
public class PersonImmutable {
public final String firstName;
public final String lastName;
public final BigDecimal salary;
public PersonImmutable(
String firstName,
String lastName,
BigDecimal salary) {
this.firstName = firstName;
this.lastName = lastName;
this.salary = salary;
}
PersonImmutable withSalary(BigDecimal newSalary) {
return new PersonImmutable(
this.firstName,
this.lastName,
newSalary);
}
}
47. Immutability inImmutability inImmutability in kotlinkotlinkotlin
data class Person(
val firstName: String,
val lastName : String,
val salary: BigDecimal)
val x:Person = ...
val y = x.copy( salary = BigDecimal("15000"))
48. Java recordsJava recordsJava records
record Person(
String firstName,
String lastName,
BigDecimal salary )
var x = ...
//val y = x.copy( salary = BigDecimal("15000"))
49. Two great things You can do to avoid bugsTwo great things You can do to avoid bugsTwo great things You can do to avoid bugs
stop using java.util. collections
prefer immutable objects
use Kotlin
53. Fantastic frameworksFantastic frameworksFantastic frameworks
What do they promise:What do they promise:What do they promise:
concentrate on business logic
let the magic work
inject whatever wherever
54. Fantastic frameworksFantastic frameworksFantastic frameworks
What they really do:What they really do:What they really do:
leaking abstractions
mess in code
hard to debug problems
null pointer exceptions
slow tests
60. What typical coder thinks when you say you doWhat typical coder thinks when you say you doWhat typical coder thinks when you say you do
not use framework to do transactionnot use framework to do transactionnot use framework to do transaction
code fromcode fromcode from
public void updateCoffeeSales(HashMap<String, Integer> salesForWeek)
throws SQLException {
PreparedStatement updateSales = null;
PreparedStatement updateTotal = null;
String updateString =
"update " + dbName + ".COFFEES " +
"set SALES = ? where COF_NAME = ?";
String updateStatement =
"update " + dbName + ".COFFEES " +
"set TOTAL = TOTAL + ? " +
"where COF_NAME = ?";
try {
con.setAutoCommit(false);
updateSales = con.prepareStatement(updateString);
updateTotal = con.prepareStatement(updateStatement);
for (Map.Entry<String, Integer> e : salesForWeek.entrySet()) {
updateSales.setInt(1, e.getValue().intValue());
updateSales.setString(2, e.getKey());
updateSales.executeUpdate();
updateTotal.setInt(1, e.getValue().intValue());
updateTotal.setString(2, e.getKey());
updateTotal.executeUpdate();
con.commit();
}
} catch (SQLException e ) {
JDBCTutorialUtilities.printSQLException(e);
if (con != null) {
try {
System.err.print("Transaction is being rolled back");
con.rollback();
} catch(SQLException excep) {
JDBCTutorialUtilities.printSQLException(excep);
}
}
} finally {
https://docs.oracle.com/javase/tutorial/jdbc/bashttps://docs.oracle.com/javase/tutorial/jdbc/bashttps://docs.oracle.com/javase/tutorial/jdbc/bas
63. Hibernate can do that as wellHibernate can do that as wellHibernate can do that as well
TransactionUtil.doInHibernate( this::sessionFactory, session -
...
session.persist( item );
...
} );
74. public void notifyGroupOwner(int userId) {
final User user = userService.getUserFromDB(10001);
final Group group = user.getGroup();
final User owner = group.getGroupOwner();
owner.sendMessage("User "+ userId
+ " is not eating mushrooms");
}
75. side e ects everywhereside e ects everywhereside e ects everywhere
public void notifyGroupOwner(int userId) {
final User user = userService.getUserFromDB(10001);
//may return null, throw exception
final Group group = user.getGroup();
// may return null, is in transaction, throws sometimes excep
final User owner = group.getGroupOwner();
//may return null, may come from cache
owner.sendMessage("User "+ userId + " to straszny niejadek!");
//called async
}
76. NULLNULLNULL - I call it my billion-dollar mistake- I call it my billion-dollar mistake- I call it my billion-dollar mistake
77. handling missing datahandling missing datahandling missing data
User user = userService.getUserFromDB(10001);
if ( user != null) {
final Group group = user.getGroup();
if ( group != null ) {
final User owner = group.getGroupOwner();
if ( owner != null ) {
owner.sendMessage("hello there!!!");
}
}
}
78. WHAT IF WE COULD MAKEWHAT IF WE COULD MAKE
PROBLEMS VISIBLE?PROBLEMS VISIBLE?
79. root of the problemroot of the problemroot of the problem
User getUserFromDB(int userId) {....
81. better,better,better,
Optional<User> user = userService.getUserFromDB(10001);
if ( user.isPresent()) {
final Optional<Group> group = user.get().getGroup();
if ( group.isPresent() ) {
final Optional<User> owner = group.get().getGroupOwner
if ( owner.isPresent() ) {
owner.sendMessage("hello there!!!");
}
}
}
82. better,better,better,
not smart at allnot smart at allnot smart at all
Optional<User> user = userService.getUserFromDB(10001);
if ( user.isPresent()) {
final Optional<Group> group = user.get().getGroup();
if ( group.isPresent() ) {
final Optional<User> owner = group.get().getGroupOwner
if ( owner.isPresent() ) {
owner.sendMessage("hello there!!!");
}
}
}
84. mapmapmap went wrongwent wrongwent wrong
Optional<User> user = userService.getUserFromDB(10001);
Optional<Optional<Group>> group = user.map(u -> u.getGroup());
85. mapmapmap went wrongwent wrongwent wrong
Optional<User> user = userService.getUserFromDB(10001);
Optional<Optional<Group>> group = user.map(u -> u.getGroup());
86. flatMapflatMapflatMap to the rescueto the rescueto the rescue
Optional<User> user = userService.getUserFromDB(10001);
Optional<Group> group = user.flatMap(u -> u.getGroup());
93. A MONADA MONAD
de nition 1 - formalde nition 1 - formalde nition 1 - formal
94. aaa monadmonadmonad in X is just a monoid in thein X is just a monoid in thein X is just a monoid in the
category of endofunctors of X, withcategory of endofunctors of X, withcategory of endofunctors of X, with
product × replaced by compositionproduct × replaced by compositionproduct × replaced by composition
of endofunctors and unit set byof endofunctors and unit set byof endofunctors and unit set by
the identity endofunctor.the identity endofunctor.the identity endofunctor.
104. FunctorFunctorFunctor - is a type(class) that has- is a type(class) that has- is a type(class) that has mapmapmap
Every monad is a functorEvery monad is a functorEvery monad is a functor
Some people call functorSome people call functorSome people call functor mappablemappablemappable
105. Applicative functorApplicative functorApplicative functor
Something between monad and functorSomething between monad and functorSomething between monad and functor
HasHasHas apapap functionfunctionfunction
ap(F<(A)->B>,F<A>)ap(F<(A)->B>,F<A>)ap(F<(A)->B>,F<A>) -> F<B>-> F<B>-> F<B>
106. MONADS, FUNCTOR MAKE SIDEMONADS, FUNCTOR MAKE SIDE
EFFECTS EXPLICITLY VISIBLE IN AEFFECTS EXPLICITLY VISIBLE IN A
TYPE SYSTEMTYPE SYSTEM
107. Applicative functor lets youApplicative functor lets youApplicative functor lets you sumsumsum inside e ectsinside e ectsinside e ects
(potentially parallel sequence)(potentially parallel sequence)(potentially parallel sequence)
Monadic atMap sequences operation one byMonadic atMap sequences operation one byMonadic atMap sequences operation one by
oneoneone
108. If You have 2 independent db transactions,If You have 2 independent db transactions,If You have 2 independent db transactions,
that can be called concurrently - You can usethat can be called concurrently - You can usethat can be called concurrently - You can use
apapap
If operations on db depend on some otherIf operations on db depend on some otherIf operations on db depend on some other
transaction (success/rollback) use atMaptransaction (success/rollback) use atMaptransaction (success/rollback) use atMap
110. It uses JDBI
one of many possible implementations (very
simple)
class Transaction<A> (private val action : (Handle) -> A ) {
fun run(dbi : Jdbi) : A = dbi.inTransaction<A, RuntimeExce
fun <B> map ( f: (A)->B) = Transaction {handle ->
f(action(handle))
}
fun <B> flatMap( f: (A)->Transaction<B>) = Transaction {h
f(action(handle)).action(handle)
}
companion object {
fun <T> pure (obj:T) = Transaction {
obj
111. Example useExample useExample use
internal fun selectNewJob () = Transaction{
dbHandle ->
dbHandle.createQuery(selectNextJobId)
.mapTo(Long::class.java)
.one()
.map { jobId ->
dbHandle.createUpdate(updateBatch).bind("b
.execute()
jobId
}
}.flatMap { jobId ->
selectNewTasks(jobId)
}
112. The same can be done with other aspectsThe same can be done with other aspectsThe same can be done with other aspects
/e ects/e ects/e ects
security
cache
diagnostics/monitoring
async
113. That is a lot ofThat is a lot ofThat is a lot of flatMapflatMapflatMap
114. Would be better if we hadWould be better if we hadWould be better if we had do notationdo notationdo notation
115. Four great things You can do to avoid bugsFour great things You can do to avoid bugsFour great things You can do to avoid bugs
stop using java.util. collections
prefer immutable objects
learn lambdas and higher order functions
use kotlin
use monads
use scala
116.
117. How do we chain multiple e ects?How do we chain multiple e ects?How do we chain multiple e ects?
the worstthe worstthe worst flatMapflatMapflatMap ever...ever...ever...
Future<Secure<Transaction<Optional<Int>>>> myX;
Function<Int, Future<Secure<Transaction<Optional<String>>>>> f
myX.flatMap(f) // ...no go
Function<Secure<Transaction<Optional<Int>>>>, Future<Secure<Tr
118. Problem of stacking monadsProblem of stacking monadsProblem of stacking monads
120. Monad transformers appeared to not be thatMonad transformers appeared to not be thatMonad transformers appeared to not be that
greatgreatgreat
We cannot have use them in kotlin or java (in aWe cannot have use them in kotlin or java (in aWe cannot have use them in kotlin or java (in a
sensible way)sensible way)sensible way)
128. class Hasiok {
@Resource
val jdbcConnection: Connection
@Transactional
@Secure
@Cacheable
@Retryable
fun f(p:P) {
//code
}
}
129. class Hasiok {
val enterprisyF = Nee.pure(
secure
.and(retryable)
.and(cacheable)
.and(transactional)) {conn:ConnectionProvider ->
{p: P ->
//code
}
}
//declaration above means security is checked before retri
//and retrial is made before cache which happens before tr
}
130. fun readStone() = Nee.pure(cached.andThen(jdbc)) { jdbcProvide
{ id: StoneId ->
val dsl = DSL.using(jdbcProvider.getConnection().g
val record = dsl.selectFrom(Stones.STONES)
.where(Stones.STONES.ID.eq(id))
.fetchOneInto(Stones.STONES)
Stone(record.id, StoneData(record.name, record.pri
}
}.anyError()
131. fun addNewStone(newStone: StoneData) = seq.next().flatMap
addStone(it, newStone)
}
private fun addStone(stoneId: Long, newStone: StoneData) =
val dsl = DSL.using(jdbcProvider.getConnection().getRe
val insertedRows = dsl.insertInto(Stones.STONES)
.values(stoneId, newStone.name, newStone.price)
.execute()
if (insertedRows == 1) {
Option.some(stoneId)
} else {
Option.none()
}
}
132. Nee is a hobby, experimental project.Nee is a hobby, experimental project.Nee is a hobby, experimental project.
NeeNeeNee monadmonadmonad has 4 params:has 4 params:has 4 params:
Nee<R,E,P,A>Nee<R,E,P,A>Nee<R,E,P,A>
- R - environment (context)
- E - error type
- P - argument (for cache - I think this was a bas idea)
- A - the real result type
133. I am slowly adding e ects:I am slowly adding e ects:I am slowly adding e ects:
jdbc,
any transactional resource,
cache,
security,
diagnostic,
136. open class DocsModule(val config: ConfigModule) {
open val dbProvider: HandleProvider by lazy {
DBProvider(config.cfg)
}
open val timeProvider: TimeProvider by lazy { RealTime }
open val jobsRepository by lazy { JobsRepository(dbProvide
open val zipWriter : StatusZipWriter by lazy {
StatusZipWriter(config)
}
open val docsStatusRepository : DocsStatusRepository by la
137. MATERIALSMATERIALS
Project ZIOProject ZIOProject ZIO
Fun(c) 2018.7: John De Goes - FP to the MaxFun(c) 2018.7: John De Goes - FP to the MaxFun(c) 2018.7: John De Goes - FP to the Max
The Book of MonadsThe Book of MonadsThe Book of Monads Alejandro Serrano MenaAlejandro Serrano MenaAlejandro Serrano Mena
(experiment)(experiment)(experiment)
https://github.com/ziohttps://github.com/ziohttps://github.com/zio
https://www.youtube.com/watch?https://www.youtube.com/watch?https://www.youtube.com/watch?
v=sxudIMiOo68v=sxudIMiOo68v=sxudIMiOo68
https://github.com/nee ect/neehttps://github.com/nee ect/neehttps://github.com/nee ect/nee
138. FUNCTIONAL PROGRAMMINGFUNCTIONAL PROGRAMMING
Power of abstractionsPower of abstractionsPower of abstractions
we want to have less bugs
we want testability
we want to have more fun
@jarek000000@jarek000000@jarek000000
Thank youThank youThank you