Last active
January 29, 2019 19:24
-
-
Save joshuakfarrar/3cdf37e97ab965fa6a7d8f7ec9121443 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Composing asynchronous calls in JavaScript can be ugly. Taking advantage of functional algebras, it doesn't have to be!