SlideShare uma empresa Scribd logo
1 de 46
MTL in Action
Monad Transformer Library
21/05/2018
2C R A F T E D B Y C O N C E N T R A
MTL type classes
3C R A F T E D B Y C O N C E N T R A
Validation failure - FunctorRaise
4C R A F T E D B Y C O N C E N T R A
Validation failure - FunctorRaise
5C R A F T E D B Y C O N C E N T R A
Events, Logs and Metrics - FunctorTell
6C R A F T E D B Y C O N C E N T R A
Events, Logs and Metrics - FunctorTell
7C R A F T E D B Y C O N C E N T R A
Interlude – Custom Ops
8C R A F T E D B Y C O N C E N T R A
Environment or read-only state – ApplicativeAsk
9C R A F T E D B Y C O N C E N T R A
Environment or read-only state – ApplicativeAsk
10C R A F T E D B Y C O N C E N T R A
Read-write State – MonadState
11C R A F T E D B Y C O N C E N T R A
Read-write State – MonadState
12C R A F T E D B Y C O N C E N T R A
Chain it all together
13C R A F T E D B Y C O N C E N T R A
Error Handling – ErrorMonad / ErrorApplicative
class MyHandledService[M[_]:
ApplicativeAsk[?[_], Connection]:
MonadState[?[_], Map[UUID, String]]:
FunctorTell[?[_], Vector[Event]]:
ApplicativeError[?[_], NonEmptyList[String]]:
Monad
]
class MyCorrectlyHandledService[M[_]:
ApplicativeAsk[?[_], Connection]:
MonadState[?[_], Map[UUID, String]]:
FunctorTell[?[_], Vector[Event]]:
MonadError[?[_], NonEmptyList[String]]
]
14C R A F T E D B Y C O N C E N T R A
Some historical context
15C R A F T E D B Y C O N C E N T R A
May 2014
• Abstraction of Monad higher kinded type
• Motivated by constant changing options for validation monads
• Implemented via use of trait mixins
• Lets pretend this never happened
16C R A F T E D B Y C O N C E N T R A
May 2016
• Abstraction of Monad higher kinded type
• Use of type classes for all monad types
• Natural Transformations to move between stacks
• Combinatorial boiler-plate nightmare
• FutureT
• Active in productive code for several years now
• https://skillsmatter.com/skillscasts/8083-functional-service-oriented-architecture
17C R A F T E D B Y C O N C E N T R A
May 2016
Reader
Monad
State
Monad
~> ~>
M[ _ ]:Error
(ReaderStateError)
18C R A F T E D B Y C O N C E N T R A
May 2018
• Abstraction of Monad higher kinded type
• Use of type classes for all monad types
• Use of composable cats MTL to create stacks
• Service flow constructed around one Higher Kinded Type
19C R A F T E D B Y C O N C E N T R A
May 2016
M[ _ ]:ErrorMonad
M[ _ ]:ApplicativeAsk M[ _ ]:StateMonad
M[ _ ]:ApplicativeAsk:StateMonad:ErrorMonad
20C R A F T E D B Y C O N C E N T R A
May 2016
21C R A F T E D B Y C O N C E N T R A
May 2016
22C R A F T E D B Y C O N C E N T R A
May 2016
23C R A F T E D B Y C O N C E N T R A
May 2016
trait KeyPersonRepo[M[_]]
class KeyPersonStateRepo[M[_]:MonadState[?[_], Map[UUID, Person]]] extends KeyPersonRepo[M[_]]
class KeyPersonSqlRepo[M[_]:ApplicativeAsk[?[_], Connection]] extends KeyPersonRepo[M[_]]
type M[A] = ReaderT[Either[String, ?], Connection, A]
UserCanAccess[M](new KeyPersonSqlRepo[M], new RoleAccessService[M])
24C R A F T E D B Y C O N C E N T R A
Service Design
25C R A F T E D B Y C O N C E N T R A
Monad Driven Service Design
val result:Either[String, (Map[UUID, Person], Boolean)] =
service.canUserAccess(uuid).run(state)
• Returning an error will drop all writer logs and state changes
• All ‘work’ is effectively annulled
• This is not necessarily a bad thing but needs to be designed for
• Unlifting errors out of the stack as explicit return type
Have to reason about abstract dependencies however
• Can change behaviour but does change how we might reason on our program
26C R A F T E D B Y C O N C E N T R A
Monad Driven Service Design
• If only a small section of the service requires a given mtl function, can you
abstract out to a dependency?
• Simplifies testing
• Primarily consider extraction for Reader, State, and IO
Minimise mtl requirements
27C R A F T E D B Y C O N C E N T R A
Monad Driven Service Design
State and Environment Products
MonadState[M, Map[String, String]]
MonadState[M, Map[String, Int]]+
MonadState[M, (Map[String, String], Map[String, Int])]
28C R A F T E D B Y C O N C E N T R A
Monad Driven Service Design
State and Environment Products
def tupleStateMonad[M[_], S <: Product, S2](implicit S:Selector[S, S2], R:Replacer[S, S2, S2], M:MonadState[M, S]):MonadState[M, S2] =
new MonadState[M, S2] {
val monad: Monad[M] = M.monad
def inspect[A](f: S2 => A):M[A] =
M.inspect(s => f(S(s)))
def modify(f: S2 => S2):M[Unit] =
M.modify(s => R(s, f(S(s))).asInstanceOf[(S2, S)]._2)
def get:M[S2] =
M.inspect(S.apply)
def set(s2: S2): M[Unit] =
M.modify(s => R(s, s2).asInstanceOf[(S2, S)]._2)
}
29C R A F T E D B Y C O N C E N T R A
Monad Driven Service Design
State and Environment Products
def tupleApplicativeAsk[M[_], E <: Product2[_,_], E2](implicit S:Selector[E, E2], A:ApplicativeAsk[M, E]):ApplicativeAsk[M, E2] =
new ApplicativeAsk[M, E2] {
val applicative: Applicative[M] =
A.applicative
def ask:M[E2] =
A.reader(S.apply)
def reader[A](f: E2 => A):M[A] =
A.reader(e => f(S(e)))
}
30C R A F T E D B Y C O N C E N T R A
Monad Driven Service Design
State and Environment Products
implicit def mInt:MonadState[M, Map[String, Int]] =
tupleStateMonad[M, (Map[String, String], Map[String, Int]), Map[String, Int]]
implicit def mString:MonadState[M, Map[String, String]] =
tupleStateMonad[M, (Map[String, String], Map[String, Int]), Map[String, String]]
https://stackoverflow.com/questions/50271244/avoid-diverging-implicit-expansion-on-recursive-mtl-class
31C R A F T E D B Y C O N C E N T R A
Monad Driven Service Design
Service Provider Pattern
class UserAnalytics[M[_]](userServiceProvider:TenantId => M[UserService[M[_]]]) {
def getUserCountForTenant(tenantId:TenantId):M[Int] = {
for {
userService <- userServiceProvider(tenantId)
count <- userService.count
} yield count
}
}
class TestUserService[M[_]:State[Map[UUID, User], ?]]
type M[A] = State[(Map[TenantId, Map[UUID, User]], Map[UUID, User]), A]
32C R A F T E D B Y C O N C E N T R A
Performance
33C R A F T E D B Y C O N C E N T R A
Performance
Simple benchmark 1000x
class Baseline {
def run = {
val a = "a"
val b = "b"
val ab = a + b
val c = "c"
val abc = ab + c
val d = "d"
val dc = d + c
val e = "e"
val f = "f"
val g = "g"
val efg = e + f + g
val h = "h"
val afh = a + f + h
val i = "i"
val j = "j"
val k = "k"
val l = "l"
val ijkl = i + j + k + l
val dijkl = d + ijkl
val m = "m"
val n = "n"
val mn = m + n
val o ="o"
ab + dc + afh + ijkl + mn + o
}
}
class MapFlatMapService[M[_]:Monad] {
def run:M[String] =
for {
a <- pure("a")
b <- pure("b")
ab = a + b
c <- pure("c")
abc = ab + c
d <- pure("d")
dc = d + c
e <- pure("e")
f <- pure("f")
g <- pure("g")
efg = e + f + g
h <- pure("h")
afh = a + f + h
i <- pure("i")
j <- pure("j")
k <- pure("k")
l <- pure("l")
ijkl = i + j + k + l
dijkl = d + ijkl
m <- pure("m")
n <- pure("n")
mn = m + n
o <- pure("o")
} yield ab + dc + afh + ijkl + mn + o
}
34C R A F T E D B Y C O N C E N T R A
Performance
Monads
0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9
Either Monad
Id Monad
Baseline
Time(ms)
35C R A F T E D B Y C O N C E N T R A
Performance
Monad Transformer Stack
0 1 2 3 4 5 6 7 8 9
ReaderTStateTWriterTEither
Either Monad
Id Monad
Baseline
Time(ms)
type M[R, S, L, E, A] = ReaderT[StateT[WriterT[Either[E, ?], L, ?], S, ?], R, A]
36C R A F T E D B Y C O N C E N T R A
Performance
ReaderWriterState Monad
0 1 2 3 4 5 6 7 8 9
ReaderWriterState
ReaderTStateTWriterTEither
Either Monad
Id Monad
Baseline
Time(ms)
final class IndexedReaderWriterStateT[F[_], E, L, SA, SB, A](val runF: F[(E, SA) => F[(L, SB, A)]]) extends Serializable {
type ReaderWriterState[E, L, S, A] = ReaderWriterStateT[Eval, E, L, S, A]
37C R A F T E D B Y C O N C E N T R A
Performance
ReaderWriterStateTEither
final class IndexedReaderWriterStateT[F[_], E, L, SA, SB, A](val runF: F[(E, SA) => F[(L, SB, A)]]) extends Serializable {
type ReaderWriterStateTEither[E, L, S, A] = ReaderWriterStateT[Either[V, ?] , E, L, S, A]
0 1 2 3 4 5 6 7 8 9
ReaderWriterStateTEither
ReaderWriterState
ReaderTStateTWriterTEither
Either Monad
Id Monad
Baseline
Time(ms)
38C R A F T E D B Y C O N C E N T R A
Performance
Service Monad
0 1 2 3 4 5 6 7 8 9
ServiceMonad
ReaderWriterStateTEither
ReaderWriterState
ReaderTStateTWriterTEither
Either Monad
Id Monad
Baseline
Time(ms)
final case class ServiceMonad[R, S, L, E, T](f:(R, S) => Either[E, (S, L, T)]) {
39C R A F T E D B Y C O N C E N T R A
Performance
Unstacked Monad
0 1 2 3 4 5 6 7 8 9
Unstacked Monad
ServiceMonad
ReaderWriterStateTEither
ReaderWriterState
ReaderTStateTWriterTEither
Either Monad
Id Monad
Baseline
Time(ms)
40C R A F T E D B Y C O N C E N T R A
Performance
Unstacked Monad
sealed trait UnstackedMonad[R, S, L, E, A]
final case class UnstackedError[R, S, L, E, A](e:E) extends UnstackedMonad[R, S, L, E, A]
final case class UnstackedPure[R, S, L, E, A](a:A) extends UnstackedMonad[R, S, L, E, A]
final case class UnstackedWriter[R, S, L, E, A](l:L, a:A) extends UnstackedMonad[R, S, L, E, A]
final case class SuccessReturn[S, L, A] private(s:S, l:L, a:A)
final case class ErrorReturn[E] private(e:E)
final case class UnstackedFunction[R, S, L, E, A](func:(R, S) => Any) extends UnstackedMonad[R, S, L, E, A]
41C R A F T E D B Y C O N C E N T R A
Performance
Unstacked Monad
final case class UnstackedError[R, S, L, E, A](e:E) extends UnstackedMonad[R, S, L, E, A]
final case class UnstackedErrorWithLog[R, S, L, E, A](l: L, e:E) extends UnstackedMonad[R, S, L, E, A]
final case class UnstackedErrorWithLogAndState[R, S, L, E, A](s:S, l:L, e:E) extends UnstackedMonad[R, S, L, E, A]
42C R A F T E D B Y C O N C E N T R A
We need to talk about Futures
43C R A F T E D B Y C O N C E N T R A
Supporting futures
trait LiftFuture[M[_]] {
def liftFuture[A](f: => Future[A]):M[A]
}
private def requestWithMethod(
method: HttpMethod,
url: String,
headers:List[HttpHeader],
contentType: ContentType,
content: Array[Byte]): M[Array[Byte]] =
for {
res <- liftFuture {
Http().singleRequest(HttpRequest(method, Uri(url), headers, HttpEntity(contentType, content)))
}
r <- status(url, res)
d <- liftFuture {
r.entity.dataBytes.runFold(ByteString(""))(_ ++ _).map(e => e.toIterator.toArray)
}
} yield d
44C R A F T E D B Y C O N C E N T R A
Supporting futures
final case class UnstackedFuture[R, S, L, E, A](func:(R, S) => Any) extends UnstackedAsyncMonad[R, S, L, E, A]
final case class SuccessReturn[S, L, A] private(s:S, l:L, a:A)
final case class ErrorReturn[E] private(e:E)
final case class FutureReturn private(f:Future[Any])
45C R A F T E D B Y C O N C E N T R A
Supporting futures
class EffectfulActorServiceWrapper[D[_], M[_], N[_]:LiftFuture:Monad]
(service: D ~> M, effect: => Effect[M, N], name:Option[String])
(implicit af:ActorRefFactory, timeout:Timeout)
extends (D ~> N) {
import akka.pattern._
val e:Effect[M, N] = effect
def props =
Props {
new Actor {
def receive: PartialFunction[Any, Unit] = {
case d: D[_]@unchecked =>
sender ! e.unsafeRun(service(d))
}
}
}
val actorRef: ActorRef = name.fold(af.actorOf(props)){ n => af.actorOf(props, n)}
def apply[A](fa: D[A]):N[A] =
implicitly[Monad[N]].flatten(implicitly[LiftFuture[N]].liftFuture(actorRef.ask(fa).asInstanceOf[Future[N[A]]]))
}
GET IN TOUCH • GET THE EDGE
Concentra Analytics
100 Cheapside
London EC2V 6DT
+44 (0)20 7099 6910 info@concentra.co.uk concentra.co.uk

Mais conteúdo relacionado

Mais procurados

Regression &amp; Classification
Regression &amp; ClassificationRegression &amp; Classification
Regression &amp; Classification
주영 송
 
Seminar PSU 09.04.2013 - 10.04.2013 MiFIT, Arbuzov Vyacheslav
Seminar PSU 09.04.2013 - 10.04.2013 MiFIT, Arbuzov VyacheslavSeminar PSU 09.04.2013 - 10.04.2013 MiFIT, Arbuzov Vyacheslav
Seminar PSU 09.04.2013 - 10.04.2013 MiFIT, Arbuzov Vyacheslav
Vyacheslav Arbuzov
 

Mais procurados (17)

Row Pattern Matching in Oracle Database 12c
Row Pattern Matching in Oracle Database 12cRow Pattern Matching in Oracle Database 12c
Row Pattern Matching in Oracle Database 12c
 
Table of Useful R commands.
Table of Useful R commands.Table of Useful R commands.
Table of Useful R commands.
 
12. Linear models
12. Linear models12. Linear models
12. Linear models
 
Oracle 12c SQL: Date Ranges
Oracle 12c SQL: Date RangesOracle 12c SQL: Date Ranges
Oracle 12c SQL: Date Ranges
 
Class program and uml in c++
Class program and uml in c++Class program and uml in c++
Class program and uml in c++
 
Regression &amp; Classification
Regression &amp; ClassificationRegression &amp; Classification
Regression &amp; Classification
 
Ranges, ranges everywhere (Oracle SQL)
Ranges, ranges everywhere (Oracle SQL)Ranges, ranges everywhere (Oracle SQL)
Ranges, ranges everywhere (Oracle SQL)
 
Row patternmatching12ctech14
Row patternmatching12ctech14Row patternmatching12ctech14
Row patternmatching12ctech14
 
Advanced row pattern matching
Advanced row pattern matchingAdvanced row pattern matching
Advanced row pattern matching
 
Dsprograms(2nd cse)
Dsprograms(2nd cse)Dsprograms(2nd cse)
Dsprograms(2nd cse)
 
Grokking Monads in Scala
Grokking Monads in ScalaGrokking Monads in Scala
Grokking Monads in Scala
 
Seminar PSU 09.04.2013 - 10.04.2013 MiFIT, Arbuzov Vyacheslav
Seminar PSU 09.04.2013 - 10.04.2013 MiFIT, Arbuzov VyacheslavSeminar PSU 09.04.2013 - 10.04.2013 MiFIT, Arbuzov Vyacheslav
Seminar PSU 09.04.2013 - 10.04.2013 MiFIT, Arbuzov Vyacheslav
 
Apache Spark™ Applications the Easy Way - Pierre Borckmans
Apache Spark™ Applications the Easy Way - Pierre BorckmansApache Spark™ Applications the Easy Way - Pierre Borckmans
Apache Spark™ Applications the Easy Way - Pierre Borckmans
 
Mat lab
Mat labMat lab
Mat lab
 
Logistic Modeling with Applications to Marketing and Credit Risk in the Autom...
Logistic Modeling with Applications to Marketing and Credit Risk in the Autom...Logistic Modeling with Applications to Marketing and Credit Risk in the Autom...
Logistic Modeling with Applications to Marketing and Credit Risk in the Autom...
 
Solution of matlab chapter 3
Solution of matlab chapter 3Solution of matlab chapter 3
Solution of matlab chapter 3
 
Computer graphics lab report with code in cpp
Computer graphics lab report with code in cppComputer graphics lab report with code in cpp
Computer graphics lab report with code in cpp
 

Semelhante a Jamie Pullar- Cats MTL in action

Pointcuts and Analysis
Pointcuts and AnalysisPointcuts and Analysis
Pointcuts and Analysis
Wiwat Ruengmee
 

Semelhante a Jamie Pullar- Cats MTL in action (20)

Learn Matlab
Learn MatlabLearn Matlab
Learn Matlab
 
Leveraging R in Big Data of Mobile Ads (R在行動廣告大數據的應用)
Leveraging R in Big Data of Mobile Ads (R在行動廣告大數據的應用)Leveraging R in Big Data of Mobile Ads (R在行動廣告大數據的應用)
Leveraging R in Big Data of Mobile Ads (R在行動廣告大數據的應用)
 
R Programming Intro
R Programming IntroR Programming Intro
R Programming Intro
 
RBootcam Day 2
RBootcam Day 2RBootcam Day 2
RBootcam Day 2
 
R Programming Homework Help
R Programming Homework HelpR Programming Homework Help
R Programming Homework Help
 
Programming in R
Programming in RProgramming in R
Programming in R
 
guia de referencia para a linguagem do fabricante CCS info_syntax.pdf
guia de referencia para a linguagem do fabricante CCS info_syntax.pdfguia de referencia para a linguagem do fabricante CCS info_syntax.pdf
guia de referencia para a linguagem do fabricante CCS info_syntax.pdf
 
Convolutional Neural Network (CNN) presentation from theory to code in Theano
Convolutional Neural Network (CNN) presentation from theory to code in TheanoConvolutional Neural Network (CNN) presentation from theory to code in Theano
Convolutional Neural Network (CNN) presentation from theory to code in Theano
 
R and data mining
R and data miningR and data mining
R and data mining
 
Basic Analysis using R
Basic Analysis using RBasic Analysis using R
Basic Analysis using R
 
Pumps, Compressors and Turbine Fault Frequency Analysis
Pumps, Compressors and Turbine Fault Frequency AnalysisPumps, Compressors and Turbine Fault Frequency Analysis
Pumps, Compressors and Turbine Fault Frequency Analysis
 
Pointcuts and Analysis
Pointcuts and AnalysisPointcuts and Analysis
Pointcuts and Analysis
 
R Language Introduction
R Language IntroductionR Language Introduction
R Language Introduction
 
Pumps, Compressors and Turbine Fault Frequency Analysis
Pumps, Compressors and Turbine Fault Frequency AnalysisPumps, Compressors and Turbine Fault Frequency Analysis
Pumps, Compressors and Turbine Fault Frequency Analysis
 
Time Series Analysis and Mining with R
Time Series Analysis and Mining with RTime Series Analysis and Mining with R
Time Series Analysis and Mining with R
 
BS LAB Manual (1).pdf
BS LAB Manual  (1).pdfBS LAB Manual  (1).pdf
BS LAB Manual (1).pdf
 
Tenser Product of Representation for the Group Cn
Tenser Product of Representation for the Group CnTenser Product of Representation for the Group Cn
Tenser Product of Representation for the Group Cn
 
Chapter 16-spreadsheet1 questions and answer
Chapter 16-spreadsheet1  questions and answerChapter 16-spreadsheet1  questions and answer
Chapter 16-spreadsheet1 questions and answer
 
【論文紹介】Relay: A New IR for Machine Learning Frameworks
【論文紹介】Relay: A New IR for Machine Learning Frameworks【論文紹介】Relay: A New IR for Machine Learning Frameworks
【論文紹介】Relay: A New IR for Machine Learning Frameworks
 
Reproducible Operations Research. An Application to Energy Systems Optimization
Reproducible Operations Research. An Application to Energy Systems OptimizationReproducible Operations Research. An Application to Energy Systems Optimization
Reproducible Operations Research. An Application to Energy Systems Optimization
 

Último

Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Victor Rentea
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Safe Software
 
Architecting Cloud Native Applications
Architecting Cloud Native ApplicationsArchitecting Cloud Native Applications
Architecting Cloud Native Applications
WSO2
 
Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire business
panagenda
 
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
?#DUbAI#??##{{(☎️+971_581248768%)**%*]'#abortion pills for sale in dubai@
 

Último (20)

"I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ..."I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...
 
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
 
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
 
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
 
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
 
Corporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptxCorporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptx
 
DBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor PresentationDBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor Presentation
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
 
Architecting Cloud Native Applications
Architecting Cloud Native ApplicationsArchitecting Cloud Native Applications
Architecting Cloud Native Applications
 
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
 
Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire business
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
 
Six Myths about Ontologies: The Basics of Formal Ontology
Six Myths about Ontologies: The Basics of Formal OntologySix Myths about Ontologies: The Basics of Formal Ontology
Six Myths about Ontologies: The Basics of Formal Ontology
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
 
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...
 
DEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
DEV meet-up UiPath Document Understanding May 7 2024 AmsterdamDEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
DEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
 
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
 
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodPolkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
 
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
 

Jamie Pullar- Cats MTL in action

  • 1. MTL in Action Monad Transformer Library 21/05/2018
  • 2. 2C R A F T E D B Y C O N C E N T R A MTL type classes
  • 3. 3C R A F T E D B Y C O N C E N T R A Validation failure - FunctorRaise
  • 4. 4C R A F T E D B Y C O N C E N T R A Validation failure - FunctorRaise
  • 5. 5C R A F T E D B Y C O N C E N T R A Events, Logs and Metrics - FunctorTell
  • 6. 6C R A F T E D B Y C O N C E N T R A Events, Logs and Metrics - FunctorTell
  • 7. 7C R A F T E D B Y C O N C E N T R A Interlude – Custom Ops
  • 8. 8C R A F T E D B Y C O N C E N T R A Environment or read-only state – ApplicativeAsk
  • 9. 9C R A F T E D B Y C O N C E N T R A Environment or read-only state – ApplicativeAsk
  • 10. 10C R A F T E D B Y C O N C E N T R A Read-write State – MonadState
  • 11. 11C R A F T E D B Y C O N C E N T R A Read-write State – MonadState
  • 12. 12C R A F T E D B Y C O N C E N T R A Chain it all together
  • 13. 13C R A F T E D B Y C O N C E N T R A Error Handling – ErrorMonad / ErrorApplicative class MyHandledService[M[_]: ApplicativeAsk[?[_], Connection]: MonadState[?[_], Map[UUID, String]]: FunctorTell[?[_], Vector[Event]]: ApplicativeError[?[_], NonEmptyList[String]]: Monad ] class MyCorrectlyHandledService[M[_]: ApplicativeAsk[?[_], Connection]: MonadState[?[_], Map[UUID, String]]: FunctorTell[?[_], Vector[Event]]: MonadError[?[_], NonEmptyList[String]] ]
  • 14. 14C R A F T E D B Y C O N C E N T R A Some historical context
  • 15. 15C R A F T E D B Y C O N C E N T R A May 2014 • Abstraction of Monad higher kinded type • Motivated by constant changing options for validation monads • Implemented via use of trait mixins • Lets pretend this never happened
  • 16. 16C R A F T E D B Y C O N C E N T R A May 2016 • Abstraction of Monad higher kinded type • Use of type classes for all monad types • Natural Transformations to move between stacks • Combinatorial boiler-plate nightmare • FutureT • Active in productive code for several years now • https://skillsmatter.com/skillscasts/8083-functional-service-oriented-architecture
  • 17. 17C R A F T E D B Y C O N C E N T R A May 2016 Reader Monad State Monad ~> ~> M[ _ ]:Error (ReaderStateError)
  • 18. 18C R A F T E D B Y C O N C E N T R A May 2018 • Abstraction of Monad higher kinded type • Use of type classes for all monad types • Use of composable cats MTL to create stacks • Service flow constructed around one Higher Kinded Type
  • 19. 19C R A F T E D B Y C O N C E N T R A May 2016 M[ _ ]:ErrorMonad M[ _ ]:ApplicativeAsk M[ _ ]:StateMonad M[ _ ]:ApplicativeAsk:StateMonad:ErrorMonad
  • 20. 20C R A F T E D B Y C O N C E N T R A May 2016
  • 21. 21C R A F T E D B Y C O N C E N T R A May 2016
  • 22. 22C R A F T E D B Y C O N C E N T R A May 2016
  • 23. 23C R A F T E D B Y C O N C E N T R A May 2016 trait KeyPersonRepo[M[_]] class KeyPersonStateRepo[M[_]:MonadState[?[_], Map[UUID, Person]]] extends KeyPersonRepo[M[_]] class KeyPersonSqlRepo[M[_]:ApplicativeAsk[?[_], Connection]] extends KeyPersonRepo[M[_]] type M[A] = ReaderT[Either[String, ?], Connection, A] UserCanAccess[M](new KeyPersonSqlRepo[M], new RoleAccessService[M])
  • 24. 24C R A F T E D B Y C O N C E N T R A Service Design
  • 25. 25C R A F T E D B Y C O N C E N T R A Monad Driven Service Design val result:Either[String, (Map[UUID, Person], Boolean)] = service.canUserAccess(uuid).run(state) • Returning an error will drop all writer logs and state changes • All ‘work’ is effectively annulled • This is not necessarily a bad thing but needs to be designed for • Unlifting errors out of the stack as explicit return type Have to reason about abstract dependencies however • Can change behaviour but does change how we might reason on our program
  • 26. 26C R A F T E D B Y C O N C E N T R A Monad Driven Service Design • If only a small section of the service requires a given mtl function, can you abstract out to a dependency? • Simplifies testing • Primarily consider extraction for Reader, State, and IO Minimise mtl requirements
  • 27. 27C R A F T E D B Y C O N C E N T R A Monad Driven Service Design State and Environment Products MonadState[M, Map[String, String]] MonadState[M, Map[String, Int]]+ MonadState[M, (Map[String, String], Map[String, Int])]
  • 28. 28C R A F T E D B Y C O N C E N T R A Monad Driven Service Design State and Environment Products def tupleStateMonad[M[_], S <: Product, S2](implicit S:Selector[S, S2], R:Replacer[S, S2, S2], M:MonadState[M, S]):MonadState[M, S2] = new MonadState[M, S2] { val monad: Monad[M] = M.monad def inspect[A](f: S2 => A):M[A] = M.inspect(s => f(S(s))) def modify(f: S2 => S2):M[Unit] = M.modify(s => R(s, f(S(s))).asInstanceOf[(S2, S)]._2) def get:M[S2] = M.inspect(S.apply) def set(s2: S2): M[Unit] = M.modify(s => R(s, s2).asInstanceOf[(S2, S)]._2) }
  • 29. 29C R A F T E D B Y C O N C E N T R A Monad Driven Service Design State and Environment Products def tupleApplicativeAsk[M[_], E <: Product2[_,_], E2](implicit S:Selector[E, E2], A:ApplicativeAsk[M, E]):ApplicativeAsk[M, E2] = new ApplicativeAsk[M, E2] { val applicative: Applicative[M] = A.applicative def ask:M[E2] = A.reader(S.apply) def reader[A](f: E2 => A):M[A] = A.reader(e => f(S(e))) }
  • 30. 30C R A F T E D B Y C O N C E N T R A Monad Driven Service Design State and Environment Products implicit def mInt:MonadState[M, Map[String, Int]] = tupleStateMonad[M, (Map[String, String], Map[String, Int]), Map[String, Int]] implicit def mString:MonadState[M, Map[String, String]] = tupleStateMonad[M, (Map[String, String], Map[String, Int]), Map[String, String]] https://stackoverflow.com/questions/50271244/avoid-diverging-implicit-expansion-on-recursive-mtl-class
  • 31. 31C R A F T E D B Y C O N C E N T R A Monad Driven Service Design Service Provider Pattern class UserAnalytics[M[_]](userServiceProvider:TenantId => M[UserService[M[_]]]) { def getUserCountForTenant(tenantId:TenantId):M[Int] = { for { userService <- userServiceProvider(tenantId) count <- userService.count } yield count } } class TestUserService[M[_]:State[Map[UUID, User], ?]] type M[A] = State[(Map[TenantId, Map[UUID, User]], Map[UUID, User]), A]
  • 32. 32C R A F T E D B Y C O N C E N T R A Performance
  • 33. 33C R A F T E D B Y C O N C E N T R A Performance Simple benchmark 1000x class Baseline { def run = { val a = "a" val b = "b" val ab = a + b val c = "c" val abc = ab + c val d = "d" val dc = d + c val e = "e" val f = "f" val g = "g" val efg = e + f + g val h = "h" val afh = a + f + h val i = "i" val j = "j" val k = "k" val l = "l" val ijkl = i + j + k + l val dijkl = d + ijkl val m = "m" val n = "n" val mn = m + n val o ="o" ab + dc + afh + ijkl + mn + o } } class MapFlatMapService[M[_]:Monad] { def run:M[String] = for { a <- pure("a") b <- pure("b") ab = a + b c <- pure("c") abc = ab + c d <- pure("d") dc = d + c e <- pure("e") f <- pure("f") g <- pure("g") efg = e + f + g h <- pure("h") afh = a + f + h i <- pure("i") j <- pure("j") k <- pure("k") l <- pure("l") ijkl = i + j + k + l dijkl = d + ijkl m <- pure("m") n <- pure("n") mn = m + n o <- pure("o") } yield ab + dc + afh + ijkl + mn + o }
  • 34. 34C R A F T E D B Y C O N C E N T R A Performance Monads 0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 Either Monad Id Monad Baseline Time(ms)
  • 35. 35C R A F T E D B Y C O N C E N T R A Performance Monad Transformer Stack 0 1 2 3 4 5 6 7 8 9 ReaderTStateTWriterTEither Either Monad Id Monad Baseline Time(ms) type M[R, S, L, E, A] = ReaderT[StateT[WriterT[Either[E, ?], L, ?], S, ?], R, A]
  • 36. 36C R A F T E D B Y C O N C E N T R A Performance ReaderWriterState Monad 0 1 2 3 4 5 6 7 8 9 ReaderWriterState ReaderTStateTWriterTEither Either Monad Id Monad Baseline Time(ms) final class IndexedReaderWriterStateT[F[_], E, L, SA, SB, A](val runF: F[(E, SA) => F[(L, SB, A)]]) extends Serializable { type ReaderWriterState[E, L, S, A] = ReaderWriterStateT[Eval, E, L, S, A]
  • 37. 37C R A F T E D B Y C O N C E N T R A Performance ReaderWriterStateTEither final class IndexedReaderWriterStateT[F[_], E, L, SA, SB, A](val runF: F[(E, SA) => F[(L, SB, A)]]) extends Serializable { type ReaderWriterStateTEither[E, L, S, A] = ReaderWriterStateT[Either[V, ?] , E, L, S, A] 0 1 2 3 4 5 6 7 8 9 ReaderWriterStateTEither ReaderWriterState ReaderTStateTWriterTEither Either Monad Id Monad Baseline Time(ms)
  • 38. 38C R A F T E D B Y C O N C E N T R A Performance Service Monad 0 1 2 3 4 5 6 7 8 9 ServiceMonad ReaderWriterStateTEither ReaderWriterState ReaderTStateTWriterTEither Either Monad Id Monad Baseline Time(ms) final case class ServiceMonad[R, S, L, E, T](f:(R, S) => Either[E, (S, L, T)]) {
  • 39. 39C R A F T E D B Y C O N C E N T R A Performance Unstacked Monad 0 1 2 3 4 5 6 7 8 9 Unstacked Monad ServiceMonad ReaderWriterStateTEither ReaderWriterState ReaderTStateTWriterTEither Either Monad Id Monad Baseline Time(ms)
  • 40. 40C R A F T E D B Y C O N C E N T R A Performance Unstacked Monad sealed trait UnstackedMonad[R, S, L, E, A] final case class UnstackedError[R, S, L, E, A](e:E) extends UnstackedMonad[R, S, L, E, A] final case class UnstackedPure[R, S, L, E, A](a:A) extends UnstackedMonad[R, S, L, E, A] final case class UnstackedWriter[R, S, L, E, A](l:L, a:A) extends UnstackedMonad[R, S, L, E, A] final case class SuccessReturn[S, L, A] private(s:S, l:L, a:A) final case class ErrorReturn[E] private(e:E) final case class UnstackedFunction[R, S, L, E, A](func:(R, S) => Any) extends UnstackedMonad[R, S, L, E, A]
  • 41. 41C R A F T E D B Y C O N C E N T R A Performance Unstacked Monad final case class UnstackedError[R, S, L, E, A](e:E) extends UnstackedMonad[R, S, L, E, A] final case class UnstackedErrorWithLog[R, S, L, E, A](l: L, e:E) extends UnstackedMonad[R, S, L, E, A] final case class UnstackedErrorWithLogAndState[R, S, L, E, A](s:S, l:L, e:E) extends UnstackedMonad[R, S, L, E, A]
  • 42. 42C R A F T E D B Y C O N C E N T R A We need to talk about Futures
  • 43. 43C R A F T E D B Y C O N C E N T R A Supporting futures trait LiftFuture[M[_]] { def liftFuture[A](f: => Future[A]):M[A] } private def requestWithMethod( method: HttpMethod, url: String, headers:List[HttpHeader], contentType: ContentType, content: Array[Byte]): M[Array[Byte]] = for { res <- liftFuture { Http().singleRequest(HttpRequest(method, Uri(url), headers, HttpEntity(contentType, content))) } r <- status(url, res) d <- liftFuture { r.entity.dataBytes.runFold(ByteString(""))(_ ++ _).map(e => e.toIterator.toArray) } } yield d
  • 44. 44C R A F T E D B Y C O N C E N T R A Supporting futures final case class UnstackedFuture[R, S, L, E, A](func:(R, S) => Any) extends UnstackedAsyncMonad[R, S, L, E, A] final case class SuccessReturn[S, L, A] private(s:S, l:L, a:A) final case class ErrorReturn[E] private(e:E) final case class FutureReturn private(f:Future[Any])
  • 45. 45C R A F T E D B Y C O N C E N T R A Supporting futures class EffectfulActorServiceWrapper[D[_], M[_], N[_]:LiftFuture:Monad] (service: D ~> M, effect: => Effect[M, N], name:Option[String]) (implicit af:ActorRefFactory, timeout:Timeout) extends (D ~> N) { import akka.pattern._ val e:Effect[M, N] = effect def props = Props { new Actor { def receive: PartialFunction[Any, Unit] = { case d: D[_]@unchecked => sender ! e.unsafeRun(service(d)) } } } val actorRef: ActorRef = name.fold(af.actorOf(props)){ n => af.actorOf(props, n)} def apply[A](fa: D[A]):N[A] = implicitly[Monad[N]].flatten(implicitly[LiftFuture[N]].liftFuture(actorRef.ask(fa).asInstanceOf[Future[N[A]]])) }
  • 46. GET IN TOUCH • GET THE EDGE Concentra Analytics 100 Cheapside London EC2V 6DT +44 (0)20 7099 6910 info@concentra.co.uk concentra.co.uk