SlideShare a Scribd company logo
1 of 81
Download to read offline
FUNCTIONS, TYPES,
PROGRAMS AND EFFECTS
QUIZHANDS UP IF YOU RECOGNIZE
A => B
A => Option[B]
Either[A,B]
A / B
A Xor B
A => M[A]
scala.concurrent.Future[+A]
scalaz.concurrent.Task[+A]
What does this do?
(maybeInt1 |@| maybeInt2) { _ > _ } | false
scalaz.SemiGroup
scalaz.Monoid
scalaz.PlusEmpty
scalaz.Functor
scalaz.Applicative
scalaz.Monad
scalaz.ApplicativePlus
scalaz.MonadPlus
Does SI-2712 ring a bell?
scalaz.Unapply[TC[_[_]], MA]
traverseU
EitherT[F[_], A, B]
OptionT[F[_], A]
What's this all about?
type E = Task |: (String / ?) |: Option |: Base
type Stack = ReaderInt |: WriterString |: Eval |: NoEffect
type PRG[A] = (Log.DSL :@: DB.DSL :@: FXNil)#Cop[A]
Free[PRG, Xor[DBError, Entity]]
Do you use scalaz or cats for your day job?
FUNCTIONS, TYPES, PROGRAMS AND EFFECTS
Strict separation of safe and unsafe
Safe: Functions, Types, creating Programs
Unsafe: Effects, running Programs
WRITING FUNCTIONAL SCALA
1. Write functions, which return values
2. Choose effects (or write your own)
3. Construct a program that composes values into effects
4. Run the program (in an 'App' in the main method)
(Not necessarily in that order)
WRITING FUNCTIONAL SCALA
▸ You can possibly have programs of programs
▸ A program is very often defined in a for comprehension
A hypothetical example.
val program = for {
client <- server.connect(details)
Exchange(src, snk) = client.exchange
_ <- snk.sendRequest(request)
in = src.pipe(text.utf8Decode)
.to(io.stdOutLines)
} yield ()
program.run
Define first, run later.
BUT FIRST: SOMETHING
ABOUT INFORMATION LOSS
QUIZKEEP IN MIND: FUNCTIONS, TYPES,
PROGRAMS, EFFECTS
Anything 'wrong' with these methods / functions?
def getUser(username: Username): Future[User]
def createUser(details: UserDetails): Future[User]
def getPrimaryAccount(user: User): Future[Account]
Anything 'wrong' with this?
def getUser(username: Username): Future[Option[User]]
def getAccounts(user: User): Future[List[Account]]
def approved(user: User, accounts: List[Account]): Future[Boolean]
DATA LOSS
Boolean blindness
Functions return values, discarding them constrains the Program 1
1
Think of the information you need later on in a for comprehension
What is 'wrong' with this?
sealed trait Error
case object UserNotFound extends Error
case object UserNameNotFound extends Error
case object AccountNotFound extends Error
def getUser(username: Username): Future[Either[Error, User]]
def getAccounts(user: User): Future[Either[Error, Account]]
scalaz Disjunction (left or right)
val res: String / Int = /-(5)
val res1: String / Int = 5.right
val moreVerbose: String / Int = 5.right[String]
val res2: String / Int = "Some error".left
val friendlier = res2.leftMap(error => s"$error has occured, we apologize.")
val res3 = res1.map(five => five * 2) // /-(10)
Map over the right
From Throwable to /
/.fromTryCatchThrowable[String, Exception] {
getDangerousString()
} // returns a Exception / String
/.fromTryCatchThrowable[String, Exception] {
getDangerousString()
}.leftMap(e=> MyError(e)) // returns a MyError / String
From A / B to X
val res: String / Int = "Error!".left
val res1 = res.fold(left=> 0, r => r)
val res2 = res.fold(left=> 0, identity) // this is the same
Why should you not use this?
Combining /
case class Error(in: Int, reason: String)
def even(in: Int): Error / Int =
if(in % 2 == 0) in.right
else Error(in, "not even").left
def divByThree(in: Int): Error / Int =
if(in % 3 == 0) in.right
else Error(in, "not div 3").left
def evenAndByThree(in: Int) =
for {
evenNr <- even(in)
byThree <- divByThree(evenNr)
} yield byThree
println(evenAndByThree(12)) // /-(12)
println(evenAndByThree(3)) // -/-(3, "not even")
println(evenAndByThree(4)) // -/-(4, "not div 3")
def evenAndByThree(in: Int) =
for {
evenNr <- even(in)
byThree <- divByThree(evenNr)
} yield byThree
No loss of information (why the first error occurred).
Given
def getUser(username: Username): Future[Error / User]]
def getAccounts(user: User): Future[Error / List[Account]]
Does this compile?
val result = for {
user <- getUser(name)
accounts <- getAccounts(user)
} yield accounts
COMBINING
EFFECTS
Combining values
Monoid - collecting / combining values into one value
//simplified / pseudo
val append: (F,F) => F
val zero: F
//actual
def append(f1: F, f2: => F): F
def zero: F
COMBINING EFFECTS
Monad - collecting / combining effects 2
def point[A](a: => A): F[A] // Creates an 'effects collector'
def bind[A, B](fa: F[A])(f: A => F[B]): F[B] // adds an effect
def map[A,B](fa: F[A])(f: A => B):F[B] // transforms input for next effect
Can only combine for same type of F.2
2
The Monad is a monoid in the category of endofunctors joke
In scalaz, flatMap is defined as:
def flatMap[B](f: A => F[B]) = F.bind(self)(f)
flatMap ~= bind
Monads are great, but in general NOT composable.
Monad Transformers
Effect systems (i.e. Eff from eff-cats)
In common, a Type that combines N Monad types
Monad Transformer EitherT
val res = for {
user <- EitherT(getUser("bla"))
accounts <- EitherT(getAccounts(user))
} yield accounts // returns EitherT[Future, Error, List[Account]]
res.run // Future[Error / List[Account]]
Scalaz provides Future Monad instance in scalaz.std.scalaFuture
Construct the Program
val res = for {
user <- EitherT(getUser("bla"))
accounts <- EitherT(getAccounts(user))
} yield accounts
Run the Program
res.run
Sometimes... a Monad Wrapper is a good enough Program
WRITE YOUR OWN MONAD
WRAPPER 3
3
specific monad transformer?
WRITE YOUR OWN MONAD WRAPPER
Topics (Kafka library)
Combine Future and /
Covariant +A/+B
Know why a Kafka operation failed in a Program
Why not EitherT?
final case class EitherT[F[_], A, B](run: F[A / B])
Invariant in A,B
Covariant Error type
sealed trait TopicsError
sealed trait FindTopicError extends TopicsError
sealed trait SelectTopicError extends TopicsError
sealed trait DeleteTopicError extends TopicsError
Example program
val program: Topics[TopicsError, Chunk[String, String]] = for {
partition ← Topics.partitioned[String, String](topicDef, partitionId)
info ← partition.write(record)
chunk ← partition.read(info.offset, info.offset)
} yield chunk
// ... somewhere later
program.run(broker, executionContext)
Minor detour (type lambda)
Monad[{ type λ[α] = Topics[E, α] })#λ]
~=
type MyMonad[T] = Monad[Topics[E, T]]
only inline.
Roll your own Monad instance (Scalaz)
object Topics {
implicit def topicsMonad[E] = new Monad[({ type λ[α] = Topics[E, α] })#λ] {
def point[T](value: T): Topics[E, T] = Topics.point(value)
def bind[T, U](topics: Topics[E, T])(f: T Topics[E, U]): Topics[E, U] = topics.flatMap(f)
}
}
delegate to point and flatMap
Roll your own Monad
case class Topics[+E, +T](run: (TopicBroker, ExecutionContext) Future[E / T]) {
// more to follow
Roll your own Monad
case class Topics[+E, +T](run: (TopicBroker, ExecutionContext) Future[E / T]) {
def map[C](f: T C): Topics[E, C] =
Topics((broker, ec) run(broker, ec).map(_.map(f))(ec))
def flatMap[E1 >: E, C](f: T Topics[E1, C]): Topics[E1, C] =
Topics { (broker, ec)
run(broker, ec).flatMap(
_.fold(err Future.successful(-/(err)), res f(res).run(broker, ec))
)(ec)
}
}
map
case class Topics[+E, +T](run: (TopicBroker, ExecutionContext) Future[E / T]) {
def map[C](f: T C): Topics[E, C] =
Topics((broker, ec) run(broker, ec).map(_.map(f))(ec))
zoom in
Topics((broker, ec) run(broker, ec).map(_.map(f))(ec))
zoom in
run(broker, ec).map(_.map(f))
flatMap
Topics { (broker, ec)
run(broker, ec).flatMap(
_.fold(err Future.successful(-/(err)), res f(res).run(broker, ec))
)(ec)
}
zoom in
run(broker, ec).flatMap(
_.fold(err Future.successful(-/(err)), res f(res).run(broker, ec))
)(ec)
zoom in
fold(err Future.successful(-/(err)), res f(res).run(broker, ec))
Convenience methods
object Topics {
def run[E, T](broker: TopicBroker, action: Topics[E, T])(implicit ec: ExecutionContext): Future[E / T] = action.run(broker, ec)
def point[T](value: T): Topics[Nothing, T] = Topics[Nothing, T]((broker, ec) Future.successful(value.right))
def future[T](action: Future[T]): Topics[Nothing, T] = Topics((broker, ec) action.map(_.right)(ec))
def futureF[T](action: ExecutionContext Future[T]): Topics[Nothing, T] = Topics((broker, ec) action(ec).map(_.right)(ec))
def either[E, T](either: E / T): Topics[E, T] = Topics((_, _) Future.successful(either))
def futureEither[E, T](action: Future[E / T]): Topics[E, T] = Topics((_, _) action)
def futureEitherF[E, T](action: ExecutionContext Future[E / T]): Topics[E, T] = Topics((_, ec) action(ec))
// ... more code
}
What about Monad Laws?
import scalaz.scalacheck.ScalazProperties.monad
class MonadLawsSpec extends Spec {
def is = s2"""obey the monad laws $laws"""
def laws = {
implicit val b = broker
monad.laws[({ type l[a] = Topics[Int, a] })#l]
}
}
Another Program example
opt-parse-applicative
"net.bmjames" %% "scala-optparse-applicative" % "0.3"
case class Config(inputFile: Option[File], outputFile: Option[File])
def main(args: Array[String]): Unit = {
val config = parseArgs(args)
// ...
}
val inputFile = optional(opt[File](
ensure[File](readStr.map(str new File(str)), "INPUT_FILE must be an existing file", _.isFile),
long("input-file"),
metavar("INPUT_FILE"),
short('f'),
help("input file to read from")
))
val outputFile = optional(opt[File](
readStr.map(str new File(str)),
long("output-file"),
metavar("OUTPUT_FILE"),
short('o'),
help("output file to write to")
))
def parseArgs(args: Array[String]): Config = {
val inputFile = optional(opt[File]( // ... omitted
val outputFile = optional(opt[File]( // ... omitted
val parser = (input |@| inputFile)(Config.apply(_, _))
execParser(args, "copy", info(parser <*> helper,
header("The awesome copy utility.")
))
}
Define the program
val parser = (input |@| inputFile)(Config.apply(_, _))
Execute the program
execParser(args, "copy", info(parser <*> helper,
header("The awesome copy utility.")
))
Some more thoughts
Scalaz has virtually no docs )-:
Scalaz has really cool stuff (-:
On a lazy Sunday..
trait MonadPlus[F[_]] extends Monad[F] with ApplicativePlus[F] { self =>
//...
/** Generalized version of Haskell's `partitionEithers` */
def separate[G[_, _], A, B](value: F[G[A, B]])(implicit G: Bifoldable[G]): (F[A], F[B]) = {
val lefts = bind(value)((aa) => G.leftFoldable.foldMap(aa)(a => point(a))(monoid[A]))
val rights = bind(value)((bb) => G.rightFoldable.foldMap(bb)(b => point(b))(monoid[B]))
(lefts, rights)
}
//...
final class MonadPlusOps[F[_],A] private[syntax](val self: F[A])(implicit val F: MonadPlus[F]) extends Ops[F[A]] {
final def separate[G[_, _], B, C](implicit ev: A === G[B, C], G: Bifoldable[G]): (F[B], F[C]) =
F.separate(ev.subst(self))
//...
You read some code..
WTF
But, separate is very useful.
def separate[G[_, _], A, B](value: F[G[A, B]])(implicit G: Bifoldable[G]): (F[A], F[B])
Remove everything, keep args and return value
(value: F[G[A, B]]): (F[A], F[B])
(value: F[G[A, B]]): (F[A], F[B])
Remove remaining 'syntax'
F[G[A, B]] => (F[A], F[B])
Lets substitute F, G, A and B to something we know
F[G[A, B]] => (F[A], F[B])
F = List
G[A,B] = Error / Result
4
4
/ uses infix type notation, same as /[Error,Result]
List[Error / Result] => (List[Error], List[Result])
It's a function to separate the errors from the results!
There are many of these.
How do you find a concrete function if they are defined in the abstract?
DIG
Remove all syntax until you are left with a function
Then find which implicits / type classes are needed for the function.
Scalaz requires you to know how the typeclasses are organized
cats project has more docs
An introduction to cats
http://typelevel.org/cats/
Advanced Scala with Cats book 5
http://underscore.io/blog
5
http://underscore.io/books/advanced-scala/
Functional Programming in Scala (the red book) 6
6
https://www.manning.com/books/functional-programming-in-scala
http://typelevel.org/blog (Some articles are really advanced)
RECAP
WRITING FUNCTIONAL SCALA
▸ Write functions
▸ Choose effects (or write your own)
▸ Construct a program that composes the functions and effects
▸ Run the program (in an 'App' in the main method)
RETURN VALUES
Use data types like A / B that do not lose information about what
happened
Boolean blindness
'Option flatMap' blindness?
PROGRAMS
Choose a reasonable architecture to construct your Programs
Monad Wrappers
Monad Transformers
Effect Systems
EOF
Functions, Types, Programs and Effects

More Related Content

What's hot

FP in Java - Project Lambda and beyond
FP in Java - Project Lambda and beyondFP in Java - Project Lambda and beyond
FP in Java - Project Lambda and beyond
Mario Fusco
 
Decorators in Python
Decorators in PythonDecorators in Python
Decorators in Python
Ben James
 
Swiss army knife Spring
Swiss army knife SpringSwiss army knife Spring
Swiss army knife Spring
Mario Fusco
 
The core libraries you always wanted - Google Guava
The core libraries you always wanted - Google GuavaThe core libraries you always wanted - Google Guava
The core libraries you always wanted - Google Guava
Mite Mitreski
 

What's hot (20)

Akka
AkkaAkka
Akka
 
FP in Java - Project Lambda and beyond
FP in Java - Project Lambda and beyondFP in Java - Project Lambda and beyond
FP in Java - Project Lambda and beyond
 
Swift 2
Swift 2Swift 2
Swift 2
 
An introduction to property based testing
An introduction to property based testingAn introduction to property based testing
An introduction to property based testing
 
Functional Programming Patterns (NDC London 2014)
Functional Programming Patterns (NDC London 2014)Functional Programming Patterns (NDC London 2014)
Functional Programming Patterns (NDC London 2014)
 
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
 
Decorators in Python
Decorators in PythonDecorators in Python
Decorators in Python
 
Google Guava for cleaner code
Google Guava for cleaner codeGoogle Guava for cleaner code
Google Guava for cleaner code
 
Google guava
Google guavaGoogle guava
Google guava
 
Google guava - almost everything you need to know
Google guava - almost everything you need to knowGoogle guava - almost everything you need to know
Google guava - almost everything you need to know
 
Composing an App with Free Monads (using Cats)
Composing an App with Free Monads (using Cats)Composing an App with Free Monads (using Cats)
Composing an App with Free Monads (using Cats)
 
Swiss army knife Spring
Swiss army knife SpringSwiss army knife Spring
Swiss army knife Spring
 
JavaScript Functions
JavaScript FunctionsJavaScript Functions
JavaScript Functions
 
The core libraries you always wanted - Google Guava
The core libraries you always wanted - Google GuavaThe core libraries you always wanted - Google Guava
The core libraries you always wanted - Google Guava
 
OOP and FP - Become a Better Programmer
OOP and FP - Become a Better ProgrammerOOP and FP - Become a Better Programmer
OOP and FP - Become a Better Programmer
 
Decorators Explained: A Powerful Tool That Should Be in Your Python Toolbelt.
Decorators Explained: A Powerful Tool That Should Be in Your Python Toolbelt.Decorators Explained: A Powerful Tool That Should Be in Your Python Toolbelt.
Decorators Explained: A Powerful Tool That Should Be in Your Python Toolbelt.
 
Advanced Debugging Using Java Bytecodes
Advanced Debugging Using Java BytecodesAdvanced Debugging Using Java Bytecodes
Advanced Debugging Using Java Bytecodes
 
Implementing the IO Monad in Scala
Implementing the IO Monad in ScalaImplementing the IO Monad in Scala
Implementing the IO Monad in Scala
 
LetSwift RxSwift 시작하기
LetSwift RxSwift 시작하기LetSwift RxSwift 시작하기
LetSwift RxSwift 시작하기
 
Python decorators
Python decoratorsPython decorators
Python decorators
 

Similar to Functions, Types, Programs and Effects

Introduction to Monads in Scala (1)
Introduction to Monads in Scala (1)Introduction to Monads in Scala (1)
Introduction to Monads in Scala (1)
stasimus
 

Similar to Functions, Types, Programs and Effects (20)

Fp in scala part 2
Fp in scala part 2Fp in scala part 2
Fp in scala part 2
 
Scala Functional Patterns
Scala Functional PatternsScala Functional Patterns
Scala Functional Patterns
 
DataWeave 2.0 - MuleSoft CONNECT 2019
DataWeave 2.0 - MuleSoft CONNECT 2019DataWeave 2.0 - MuleSoft CONNECT 2019
DataWeave 2.0 - MuleSoft CONNECT 2019
 
Fp in scala with adts part 2
Fp in scala with adts part 2Fp in scala with adts part 2
Fp in scala with adts part 2
 
Principled Error Handling with FP
Principled Error Handling with FPPrincipled Error Handling with FP
Principled Error Handling with FP
 
Monads and friends demystified
Monads and friends demystifiedMonads and friends demystified
Monads and friends demystified
 
Practical cats
Practical catsPractical cats
Practical cats
 
The Essence of the Iterator Pattern (pdf)
The Essence of the Iterator Pattern (pdf)The Essence of the Iterator Pattern (pdf)
The Essence of the Iterator Pattern (pdf)
 
The Essence of the Iterator Pattern
The Essence of the Iterator PatternThe Essence of the Iterator Pattern
The Essence of the Iterator Pattern
 
Functional programming
Functional programmingFunctional programming
Functional programming
 
Quark: A Purely-Functional Scala DSL for Data Processing & Analytics
Quark: A Purely-Functional Scala DSL for Data Processing & AnalyticsQuark: A Purely-Functional Scala DSL for Data Processing & Analytics
Quark: A Purely-Functional Scala DSL for Data Processing & Analytics
 
Introduction to Monads in Scala (1)
Introduction to Monads in Scala (1)Introduction to Monads in Scala (1)
Introduction to Monads in Scala (1)
 
Functions In Scala
Functions In Scala Functions In Scala
Functions In Scala
 
Generic Functional Programming with Type Classes
Generic Functional Programming with Type ClassesGeneric Functional Programming with Type Classes
Generic Functional Programming with Type Classes
 
1. Ch_1 SL_1_Intro to Matlab.pptx
1. Ch_1 SL_1_Intro to Matlab.pptx1. Ch_1 SL_1_Intro to Matlab.pptx
1. Ch_1 SL_1_Intro to Matlab.pptx
 
Very basic functional design patterns
Very basic functional design patternsVery basic functional design patterns
Very basic functional design patterns
 
Basic R Data Manipulation
Basic R Data ManipulationBasic R Data Manipulation
Basic R Data Manipulation
 
Introduction to matlab
Introduction to matlabIntroduction to matlab
Introduction to matlab
 
Use Applicative where applicable!
Use Applicative where applicable!Use Applicative where applicable!
Use Applicative where applicable!
 
Principled Error Handling - Scalapeño
Principled Error Handling - ScalapeñoPrincipled Error Handling - Scalapeño
Principled Error Handling - Scalapeño
 

Recently uploaded

%+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
 
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
masabamasaba
 
%+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
 
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM TechniquesAI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
VictorSzoltysek
 
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdfintroduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
VishalKumarJha10
 

Recently uploaded (20)

%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
 
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
 
%+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...
 
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
 
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
 
Exploring the Best Video Editing App.pdf
Exploring the Best Video Editing App.pdfExploring the Best Video Editing App.pdf
Exploring the Best Video Editing App.pdf
 
%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 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
 
%+27788225528 love spells in Vancouver Psychic Readings, Attraction spells,Br...
%+27788225528 love spells in Vancouver Psychic Readings, Attraction spells,Br...%+27788225528 love spells in Vancouver Psychic Readings, Attraction spells,Br...
%+27788225528 love spells in Vancouver Psychic Readings, Attraction spells,Br...
 
8257 interfacing 2 in microprocessor for btech students
8257 interfacing 2 in microprocessor for btech students8257 interfacing 2 in microprocessor for btech students
8257 interfacing 2 in microprocessor for btech students
 
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
 
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
 
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 🔝✔️✔️
 
%+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...
 
Software Quality Assurance Interview Questions
Software Quality Assurance Interview QuestionsSoftware Quality Assurance Interview Questions
Software Quality Assurance Interview Questions
 
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
Direct Style Effect Systems -The Print[A] Example- A Comprehension AidDirect Style Effect Systems -The Print[A] Example- A Comprehension Aid
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
 
The Top App Development Trends Shaping the Industry in 2024-25 .pdf
The Top App Development Trends Shaping the Industry in 2024-25 .pdfThe Top App Development Trends Shaping the Industry in 2024-25 .pdf
The Top App Development Trends Shaping the Industry in 2024-25 .pdf
 
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM TechniquesAI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
 
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdfintroduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
 
AI & Machine Learning Presentation Template
AI & Machine Learning Presentation TemplateAI & Machine Learning Presentation Template
AI & Machine Learning Presentation Template
 

Functions, Types, Programs and Effects

  • 2. QUIZHANDS UP IF YOU RECOGNIZE
  • 3. A => B A => Option[B]
  • 5. A / B A Xor B
  • 9. What does this do? (maybeInt1 |@| maybeInt2) { _ > _ } | false
  • 13. Does SI-2712 ring a bell? scalaz.Unapply[TC[_[_]], MA] traverseU
  • 15. What's this all about? type E = Task |: (String / ?) |: Option |: Base type Stack = ReaderInt |: WriterString |: Eval |: NoEffect type PRG[A] = (Log.DSL :@: DB.DSL :@: FXNil)#Cop[A] Free[PRG, Xor[DBError, Entity]]
  • 16. Do you use scalaz or cats for your day job?
  • 17. FUNCTIONS, TYPES, PROGRAMS AND EFFECTS Strict separation of safe and unsafe Safe: Functions, Types, creating Programs Unsafe: Effects, running Programs
  • 18. WRITING FUNCTIONAL SCALA 1. Write functions, which return values 2. Choose effects (or write your own) 3. Construct a program that composes values into effects 4. Run the program (in an 'App' in the main method) (Not necessarily in that order)
  • 19. WRITING FUNCTIONAL SCALA ▸ You can possibly have programs of programs ▸ A program is very often defined in a for comprehension
  • 20. A hypothetical example. val program = for { client <- server.connect(details) Exchange(src, snk) = client.exchange _ <- snk.sendRequest(request) in = src.pipe(text.utf8Decode) .to(io.stdOutLines) } yield () program.run Define first, run later.
  • 21. BUT FIRST: SOMETHING ABOUT INFORMATION LOSS
  • 22. QUIZKEEP IN MIND: FUNCTIONS, TYPES, PROGRAMS, EFFECTS
  • 23. Anything 'wrong' with these methods / functions? def getUser(username: Username): Future[User] def createUser(details: UserDetails): Future[User] def getPrimaryAccount(user: User): Future[Account]
  • 24. Anything 'wrong' with this? def getUser(username: Username): Future[Option[User]] def getAccounts(user: User): Future[List[Account]] def approved(user: User, accounts: List[Account]): Future[Boolean]
  • 25. DATA LOSS Boolean blindness Functions return values, discarding them constrains the Program 1 1 Think of the information you need later on in a for comprehension
  • 26. What is 'wrong' with this? sealed trait Error case object UserNotFound extends Error case object UserNameNotFound extends Error case object AccountNotFound extends Error def getUser(username: Username): Future[Either[Error, User]] def getAccounts(user: User): Future[Either[Error, Account]]
  • 27. scalaz Disjunction (left or right) val res: String / Int = /-(5) val res1: String / Int = 5.right val moreVerbose: String / Int = 5.right[String] val res2: String / Int = "Some error".left val friendlier = res2.leftMap(error => s"$error has occured, we apologize.") val res3 = res1.map(five => five * 2) // /-(10) Map over the right
  • 28. From Throwable to / /.fromTryCatchThrowable[String, Exception] { getDangerousString() } // returns a Exception / String /.fromTryCatchThrowable[String, Exception] { getDangerousString() }.leftMap(e=> MyError(e)) // returns a MyError / String
  • 29. From A / B to X val res: String / Int = "Error!".left val res1 = res.fold(left=> 0, r => r) val res2 = res.fold(left=> 0, identity) // this is the same Why should you not use this?
  • 30. Combining / case class Error(in: Int, reason: String) def even(in: Int): Error / Int = if(in % 2 == 0) in.right else Error(in, "not even").left def divByThree(in: Int): Error / Int = if(in % 3 == 0) in.right else Error(in, "not div 3").left def evenAndByThree(in: Int) = for { evenNr <- even(in) byThree <- divByThree(evenNr) } yield byThree println(evenAndByThree(12)) // /-(12) println(evenAndByThree(3)) // -/-(3, "not even") println(evenAndByThree(4)) // -/-(4, "not div 3")
  • 31. def evenAndByThree(in: Int) = for { evenNr <- even(in) byThree <- divByThree(evenNr) } yield byThree No loss of information (why the first error occurred).
  • 32. Given def getUser(username: Username): Future[Error / User]] def getAccounts(user: User): Future[Error / List[Account]] Does this compile? val result = for { user <- getUser(name) accounts <- getAccounts(user) } yield accounts
  • 34. Combining values Monoid - collecting / combining values into one value //simplified / pseudo val append: (F,F) => F val zero: F //actual def append(f1: F, f2: => F): F def zero: F
  • 35. COMBINING EFFECTS Monad - collecting / combining effects 2 def point[A](a: => A): F[A] // Creates an 'effects collector' def bind[A, B](fa: F[A])(f: A => F[B]): F[B] // adds an effect def map[A,B](fa: F[A])(f: A => B):F[B] // transforms input for next effect Can only combine for same type of F.2 2 The Monad is a monoid in the category of endofunctors joke
  • 36. In scalaz, flatMap is defined as: def flatMap[B](f: A => F[B]) = F.bind(self)(f) flatMap ~= bind
  • 37. Monads are great, but in general NOT composable. Monad Transformers Effect systems (i.e. Eff from eff-cats) In common, a Type that combines N Monad types
  • 38. Monad Transformer EitherT val res = for { user <- EitherT(getUser("bla")) accounts <- EitherT(getAccounts(user)) } yield accounts // returns EitherT[Future, Error, List[Account]] res.run // Future[Error / List[Account]] Scalaz provides Future Monad instance in scalaz.std.scalaFuture
  • 39. Construct the Program val res = for { user <- EitherT(getUser("bla")) accounts <- EitherT(getAccounts(user)) } yield accounts Run the Program res.run
  • 40. Sometimes... a Monad Wrapper is a good enough Program
  • 41. WRITE YOUR OWN MONAD WRAPPER 3 3 specific monad transformer?
  • 42. WRITE YOUR OWN MONAD WRAPPER Topics (Kafka library) Combine Future and / Covariant +A/+B Know why a Kafka operation failed in a Program
  • 43. Why not EitherT? final case class EitherT[F[_], A, B](run: F[A / B]) Invariant in A,B
  • 44. Covariant Error type sealed trait TopicsError sealed trait FindTopicError extends TopicsError sealed trait SelectTopicError extends TopicsError sealed trait DeleteTopicError extends TopicsError
  • 45. Example program val program: Topics[TopicsError, Chunk[String, String]] = for { partition ← Topics.partitioned[String, String](topicDef, partitionId) info ← partition.write(record) chunk ← partition.read(info.offset, info.offset) } yield chunk // ... somewhere later program.run(broker, executionContext)
  • 46. Minor detour (type lambda) Monad[{ type λ[α] = Topics[E, α] })#λ] ~= type MyMonad[T] = Monad[Topics[E, T]] only inline.
  • 47. Roll your own Monad instance (Scalaz) object Topics { implicit def topicsMonad[E] = new Monad[({ type λ[α] = Topics[E, α] })#λ] { def point[T](value: T): Topics[E, T] = Topics.point(value) def bind[T, U](topics: Topics[E, T])(f: T Topics[E, U]): Topics[E, U] = topics.flatMap(f) } } delegate to point and flatMap
  • 48. Roll your own Monad case class Topics[+E, +T](run: (TopicBroker, ExecutionContext) Future[E / T]) { // more to follow
  • 49. Roll your own Monad case class Topics[+E, +T](run: (TopicBroker, ExecutionContext) Future[E / T]) { def map[C](f: T C): Topics[E, C] = Topics((broker, ec) run(broker, ec).map(_.map(f))(ec)) def flatMap[E1 >: E, C](f: T Topics[E1, C]): Topics[E1, C] = Topics { (broker, ec) run(broker, ec).flatMap( _.fold(err Future.successful(-/(err)), res f(res).run(broker, ec)) )(ec) } }
  • 50. map
  • 51. case class Topics[+E, +T](run: (TopicBroker, ExecutionContext) Future[E / T]) { def map[C](f: T C): Topics[E, C] = Topics((broker, ec) run(broker, ec).map(_.map(f))(ec)) zoom in Topics((broker, ec) run(broker, ec).map(_.map(f))(ec)) zoom in run(broker, ec).map(_.map(f))
  • 53. Topics { (broker, ec) run(broker, ec).flatMap( _.fold(err Future.successful(-/(err)), res f(res).run(broker, ec)) )(ec) } zoom in run(broker, ec).flatMap( _.fold(err Future.successful(-/(err)), res f(res).run(broker, ec)) )(ec) zoom in fold(err Future.successful(-/(err)), res f(res).run(broker, ec))
  • 54. Convenience methods object Topics { def run[E, T](broker: TopicBroker, action: Topics[E, T])(implicit ec: ExecutionContext): Future[E / T] = action.run(broker, ec) def point[T](value: T): Topics[Nothing, T] = Topics[Nothing, T]((broker, ec) Future.successful(value.right)) def future[T](action: Future[T]): Topics[Nothing, T] = Topics((broker, ec) action.map(_.right)(ec)) def futureF[T](action: ExecutionContext Future[T]): Topics[Nothing, T] = Topics((broker, ec) action(ec).map(_.right)(ec)) def either[E, T](either: E / T): Topics[E, T] = Topics((_, _) Future.successful(either)) def futureEither[E, T](action: Future[E / T]): Topics[E, T] = Topics((_, _) action) def futureEitherF[E, T](action: ExecutionContext Future[E / T]): Topics[E, T] = Topics((_, ec) action(ec)) // ... more code }
  • 56. import scalaz.scalacheck.ScalazProperties.monad class MonadLawsSpec extends Spec { def is = s2"""obey the monad laws $laws""" def laws = { implicit val b = broker monad.laws[({ type l[a] = Topics[Int, a] })#l] } }
  • 57. Another Program example opt-parse-applicative "net.bmjames" %% "scala-optparse-applicative" % "0.3"
  • 58. case class Config(inputFile: Option[File], outputFile: Option[File]) def main(args: Array[String]): Unit = { val config = parseArgs(args) // ... }
  • 59. val inputFile = optional(opt[File]( ensure[File](readStr.map(str new File(str)), "INPUT_FILE must be an existing file", _.isFile), long("input-file"), metavar("INPUT_FILE"), short('f'), help("input file to read from") )) val outputFile = optional(opt[File]( readStr.map(str new File(str)), long("output-file"), metavar("OUTPUT_FILE"), short('o'), help("output file to write to") ))
  • 60. def parseArgs(args: Array[String]): Config = { val inputFile = optional(opt[File]( // ... omitted val outputFile = optional(opt[File]( // ... omitted val parser = (input |@| inputFile)(Config.apply(_, _)) execParser(args, "copy", info(parser <*> helper, header("The awesome copy utility.") )) }
  • 61. Define the program val parser = (input |@| inputFile)(Config.apply(_, _)) Execute the program execParser(args, "copy", info(parser <*> helper, header("The awesome copy utility.") ))
  • 63. Scalaz has virtually no docs )-:
  • 64. Scalaz has really cool stuff (-:
  • 65. On a lazy Sunday.. trait MonadPlus[F[_]] extends Monad[F] with ApplicativePlus[F] { self => //... /** Generalized version of Haskell's `partitionEithers` */ def separate[G[_, _], A, B](value: F[G[A, B]])(implicit G: Bifoldable[G]): (F[A], F[B]) = { val lefts = bind(value)((aa) => G.leftFoldable.foldMap(aa)(a => point(a))(monoid[A])) val rights = bind(value)((bb) => G.rightFoldable.foldMap(bb)(b => point(b))(monoid[B])) (lefts, rights) } //... final class MonadPlusOps[F[_],A] private[syntax](val self: F[A])(implicit val F: MonadPlus[F]) extends Ops[F[A]] { final def separate[G[_, _], B, C](implicit ev: A === G[B, C], G: Bifoldable[G]): (F[B], F[C]) = F.separate(ev.subst(self)) //... You read some code..
  • 66. WTF
  • 67. But, separate is very useful. def separate[G[_, _], A, B](value: F[G[A, B]])(implicit G: Bifoldable[G]): (F[A], F[B]) Remove everything, keep args and return value (value: F[G[A, B]]): (F[A], F[B])
  • 68. (value: F[G[A, B]]): (F[A], F[B]) Remove remaining 'syntax' F[G[A, B]] => (F[A], F[B])
  • 69. Lets substitute F, G, A and B to something we know F[G[A, B]] => (F[A], F[B]) F = List G[A,B] = Error / Result 4 4 / uses infix type notation, same as /[Error,Result]
  • 70. List[Error / Result] => (List[Error], List[Result]) It's a function to separate the errors from the results!
  • 71. There are many of these. How do you find a concrete function if they are defined in the abstract?
  • 72. DIG Remove all syntax until you are left with a function Then find which implicits / type classes are needed for the function. Scalaz requires you to know how the typeclasses are organized
  • 73. cats project has more docs An introduction to cats http://typelevel.org/cats/ Advanced Scala with Cats book 5 http://underscore.io/blog 5 http://underscore.io/books/advanced-scala/
  • 74. Functional Programming in Scala (the red book) 6 6 https://www.manning.com/books/functional-programming-in-scala
  • 76. RECAP
  • 77. WRITING FUNCTIONAL SCALA ▸ Write functions ▸ Choose effects (or write your own) ▸ Construct a program that composes the functions and effects ▸ Run the program (in an 'App' in the main method)
  • 78. RETURN VALUES Use data types like A / B that do not lose information about what happened Boolean blindness 'Option flatMap' blindness?
  • 79. PROGRAMS Choose a reasonable architecture to construct your Programs Monad Wrappers Monad Transformers Effect Systems
  • 80. EOF