Always great to see functional programming blogs! :)
Monad is too strong an abstraction for most of these examples though. In the case of
getFullName2, there is no dependency between
getLastName(user) so you can simply use Applicative instead:
Applicative[Option].map2(getFirstName(user), getLastName(user))((firstName, lastName) => s"$firstName:$lastName")
This is less a problem for
Option, but when it comes to
Future, using Applicative gives a tangible difference in performance (for instance in
concatWebPages2) . Applicative allows the
Futures to fire off in parallel, as opposed to sequentially, because there is no dependency between each computation.
Additionally, if you had many
Future[Option[T]] stacks that are independent computations,
Applicative[Future].compose[Option] will allow you to compose them easily without nested flatMaps.