Monads are functional programming abstractions that allow computations to be structured and composed in a purely functional way. They provide a way to compose functions of different types by lifting them to work on a computational context. Functors are containers that lift functions of one argument to work on their context. Applicative functors generalize this to lift functions of multiple arguments. Monads build on applicative functors by allowing computations to be chained sequentially through flatMap. In Scala, monadic code can be written using for-comprehensions, which recognize monadic patterns.
22. Monads in a purely functional language
(Haskell)
Monads in Scala
23. case class Identity[A](value: A) {
def map[B](f: A => B) = Identity(f(value))
def flatMap[B](f: A => Identity[B]) (value)
def unit(a: A) = Identity(a)
}
25. case class Writer[Log, A](log: Log, value: A) {
def map[B](f: A => B) = Writer(log, f(value))
def flatMap[B](f: A => Writer[Log, B])(m: Monoid[Log]) = {
val x: Writer[Log,B] = f(value)
Writer(m.append(log, x.log), x.value)
}
def unit[Log, A](value: A)(m: Monoid[Log]) =
Writer(m.empty, value)
}
26. def main(args: Array[String]) {
val start = 3
val finalWriter =
for(a <- addOne(start);
b <- intString(a);
c <- lengthGreaterThan5(b);
d <- noLog(oneOrZero(c));
e <- squareOf(d)
) yield e
}
¡°Adding one to 3.
Changing 4 to a String.
Checking if length is greater than 5.
Squaring 1.¡±
30. val first = List(1)
val second = List(4)
val third = List(8)
for { first flatMap {
x <- first x => second flatMap {
y <- second y=> third map {
z <- third z => x + y + z
} )
yield ( x + y + z) )
)
31. case class Transaction(memberInfo: Option[MemberInfo], id: String)
case class MemberInfo(privateInfo: Option[PrivateMember], birthdate:
String)
case class PrivateInfo(socialSecurityNumber: String)
val ssNumber = ¡°389-39-2983¡±
val priv = PrivateInfo(ssNumber)
val member = MemberInfo(priv, ¡°10-20-87¡±)
val optionalTransaction = Transaction(member, ¡°28948¡±)
for {
transaction <- optionalTransaction
memberInfo <- transaction.memberInfo
privInformation <- memberInfo.privateInfo
}
yield privInformation.socialSecurityNumber