Skip to content

Instantly share code, notes, and snippets.

@joshuakfarrar
Last active January 29, 2019 19:24
Show Gist options
  • Select an option

  • Save joshuakfarrar/3cdf37e97ab965fa6a7d8f7ec9121443 to your computer and use it in GitHub Desktop.

Select an option

Save joshuakfarrar/3cdf37e97ab965fa6a7d8f7ec9121443 to your computer and use it in GitHub Desktop.
import cats.effect.IO
import cats.Monad
import api.AirlinesService
import api.ProfilesService
import api.TripService
/*
* ok, let's say we have our services, but instead of Promises, this is Scala,
* so our services return IOs of responses as such:
*
* `AirlinesService.get[IO]` is of type IO[AirlinesResponse]
* `ProfilesService.get[IO]` is of type IO[ProfilesResponse]
* `TripService.get[IO]` is of type IO[TripResponse]
*
* The IO type simply represents the encoding of some effectful function,
* such as performing IO, making an api call, with a type
*
* What's neat about IO types is that because they obey the monad laws,
* we can compose their wrapped values into a single IO:
*/
// (F[_] is a higher-kinded type; when we pass in IO, F[_] comes to represent IO
// the implicit type guard ensures that F is monadic, that it obeys the monad laws, and can be
// composed via flatMap and map, or the syntactic sugar of a for-comprehension)
def getPassengerInfo[F[_]](implicit F: Monad[F]): F[PassengerInfo] =
for {
airlines <- AirlineService.get[F] // IO[AirlinesResponse] becomes "airlines", which is of type AirlinesResponse
profiles <- ProfilesService.get[F] // IO[ProfilesResponse] becomes "profiles", which is of type ProfilesResponse
trips <- TripService.get[F] // IO[TripResponse] becomes "trips", which is of type TripResponse
} yield constructInfo(profiles, airlines, trips)
// constructInfo is a pure function which accepts our api responses and returns a PassengerInfo DTO from them
// PassengerInfo is likely a case class which can be easily serialized for transport with a serializer from
// argonaut or circe.
// by calling constuctInfo in the `yield` portion of our for comprehension, we "lift" its return value
// into the type of the for-comprehension, in this case F, so that getPassengerInfo returns F[PassengerInfo]
def constructInfo(ar: AirlinesResponse, pr: ProfilesResponse, tr: TripResponse): PassengerInfo = ???
// getPassengerInfo[IO] returns IO[PassengerInfo], which we can execute
// "at the end of the world" to retreive its wrapped value, with none of the
// mess of composing promises in JavaScript!
getPassengerInfo[IO].unsafeRunSync
@joshuakfarrar

Copy link
Copy Markdown
Author

Composing asynchronous calls in JavaScript can be ugly. Taking advantage of functional algebras, it doesn't have to be!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment