M.
Appendix M: Chapter 14 Exercise Solutions
Written by Massimo Carli
Exercise 14.1
ResultAp<E, T> is very similar to Either<E, T>. Can you implement flatMap for it as well?
Exercise 14.1 solution
A possible flatMap implementation for ResultAp<E, T> is the following:
fun <E : Throwable, B, D> ResultAp<E, B>.flatMap(
fn: (B) -> ResultAp<E, D>
): ResultAp<E, D> = // 1
when (this) {
is Error<E> -> ResultAp.error(error) // 2
is Success<B> -> { // 3
val result = fn(value)
when (result) {
is Error<E> -> ResultAp.error(result.error) // 4
is Success<D> -> ResultAp.success(result.value) // 4
}
}
}
In the code, you replaced:
-
Either<E, T>withResult<E: Throwable, T>. -
Left<E>withError<E> -
Right<T>withSuccess<T>. -
leftwitherrorandrightwithsuccess.
As a quick note, notice that this flatMap implementation uses the fail fast approach.
Exercise 14.2
In the previous paragraphs, you implemented a simple system to fetch and parse data using both Optional<T> and Either<E, T>. Can you do the same using ResultAp<E, T>?
Exercise 14.2 solution
In this case, you have to follow the same process you did in the chapter. Start with the implementation of the following functions to fetch and parse the content:
fun fetchTvShowResultAp(
query: String
): ResultAp<IOException, String> = try {
ResultAp.success(TvShowFetcher.fetch(query))
} catch (ioe: IOException) {
ResultAp.error(ioe)
}
/** Invokes the parser returning a ResultAp<E, T> */
fun parseTvShowResultAp(
json: String
): ResultAp<SerializationException, List<ScoredShow>> = try {
ResultAp.success(TvShowParser.parse(json))
} catch (e: SerializationException) {
ResultAp.error(e)
}
Here, you just do the same replacements you did in Exercise 14.1.
The next step is the composition of fetchTvShowResultAp and parseTvShowResultAp, like this:
fun fetchAndParseTvShowResultAp(query: String) =
fetchTvShowResultAp(query)
.flatMap(::parseTvShowResultAp)
Finally, you can run the following code to test your solution:
fun main() {
fetchAndParseTvShowResultAp("Big Bang Theory")
.errorMap {
println("Error: $it")
it
}
.successMap {
println("Result: $it")
}
}
Just note that Throwable as an upper bound forces you to return a Throwable from errorMap. Again, feel free to remove that limitation if this bothers you.