Bottom of the Rabbit Hole: for-comprehensions and monads

case class Contact(id: Int, name: String, phone: Option[String], 
email: Option[String], friendIds: List[Int])
def dbLookup(id: Int): Try[Contact] = ???
def inviteFriends: List[Int] = {

var successes: List[Int] = List.empty

for (id <- friendIds) {
val record = dbLookup(id)
if (record.isSuccess) {
val maybeEmail = record.get.email
if (maybeEmail.isDefined) {
val send = sendEmail(maybeEmail.get)
if (send) successes = id :: successes
}
}
}

successes
}
def inviteFriends: List[Int] =
friendIds
.flatMap(id => dbLookup(id).toOption
.flatMap(contact => contact.email)
.filter(sendEmail).map(_ => id))

Introducing for-comprehensions

for (id <- friendIds) {
???
}
def inviteFriends: List[Int] = {

val successes = for {
id <- friendIds
contact <- dbLookup(id).toOption
emailAddr <- contact.email
if sendEmail(email)
} yield(id)

successes
}
def inviteFriends: List[Int] = {
for {
id <- friendIds
contact <- dbLookup(id).toOption
emailAddr <- contact.email
if sendEmail(emailAddr)
} yield(id)
}
val successes = friendIds
.flatMap(id => dbLookup(id).toOption
.flatMap(contact => contact.email)
.filter(sendEmail).map(_ => id))
val successes = friendIds
.flatMap(id => dbLookup(id).toOption
.map(contact => contact.email)
.filter(sendEmail).map(_ => id))
def inviteFriends: List[Int] = {
for {
id <- friendIds
contact <- dbLookup(id).toOption
emailAddr = contact.email
if sendEmail(emailAddr)
} yield(id)
}

Unveiling my Evil Master Plan

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store