beginner
I have:
F<A>
.(A) -> F<B>
.I want to have:
F<B>
.In order to have a value of F<B>
we need to run the provided function, but we need an input for it. This input may be obtained from F<A>
, but the type does not match with the requirement of the function.
Fortunately, we have the flatMap
function, present in the Monad type class. It will be able to access the internals of the effect, and feed the value to the provided function.
Consider the following value and function:
let conferenceOption = Option.some(Conference(title: "WWDC"))
// Provides the next talk for a Conference, if it exists.
func nextTalk(at conference: Conference) -> Option<Talk>
The function nextTalk
lets us retrieve the next talk for a given conference. However, we do not have a conference itself, but an Option<Conference>
. We can use the flatMap
operation to achieve our goal:
let talkOption = conferenceOption.flatMap { conference in
nextTalk(at: conference)
}
I have:
F<A>
.F<B>
.I want to have:
F<B>
, which should be run only if F<A>
is successful.We could use the flatMap
operation here by providing a function that ignores the input and yields the constant value of type F<B>
. However, the Monad type class provides a convenience function called followedBy
that takes a constant value instead of a function, and has the same semantics as flatMap
.
This function can be useful when we want to apply an effect conditionally after successfully applying another one. An example of this could be printing a message to the console when another effect finishes successfully:
// Performs a network call, returning an error or the content of the response
func networkCall() -> IO<Error, String>
let program: IO<Error, Void> = networkCall()
.followedBy(ConsoleIO.print("Finished successfully"))^
This provides a single IO<Error, Void>
that will print the message if the network call finishes successfully, and will not print anything in case the network call fails with an error.
I have:
F<A>
.(A) -> F<B>
.I want to have:
F<A>
, but performing the effect given by the function.The followedBy
function does not let us access the results of the previous effect, or return it as a result. If we want to do that, the Monad type class provides the flatTap
function. Its behavior is like flatMap
, but disregarding the result of the second effect and keeping the first.
The flatTap
operation is useful, for instance, to print some log messages. Using the previous network call example:
let loggedResponse: IO<Error, String> = networkCall()
.flatTap { response in
ConsoleIO.print("Response from call: \(response)")
}^
This way, the log is executed if the network call is successful, and still lets us chain other operations to work with its response.