# Solutions to "Scala with Cats": Chapter 4

April 4, 2023These are my solutions to the exercises of chapter 4 of Scala with Cats.

## Table of Contents

- Exercise 4.1.2: Getting Func-y
- Exercise 4.3.1: Monadic Secret Identities
- Exercise 4.4.5: What is Best?
- Exercise 4.5.4: Abstracting
- Exercise 4.6.5: Safer Folding using Eval
- Exercise 4.7.3: Show Your Working
- Exercise 4.8.3: Hacking on Readers
- Exercise 4.9.3: Post-Order Calculator
- Exercise 4.10.1: Branching out Further with Monads

## Exercise 4.1.2: Getting Func-y

We have `pure`

and `flatMap`

to define `map`

. We want to start from an `F[A]`

and get to an `F[B]`

from a function `A => B`

. As such, we want to call
`flatMap`

over the value. We can’t use `func`

directly, though. However, we can
produce a function that would lift our value to an `F`

using `pure`

(```
a =>
pure(func(a))
```

):

## Exercise 4.3.1: Monadic Secret Identities

`pure`

, `map`

and `flatMap`

for `Id`

can be implemented as follows:

Since `Id[A]`

is just a type alias for `A`

, we can notice that we avoid all
boxing in the implementations and, due to that fact, `flatMap`

and `map`

are
identical.

## Exercise 4.4.5: What is Best?

The answer depends on what we are looking for in specific instances, but some things that the previous examples for error handling don’t cover are:

- We can’t accumulate errors. The proposed examples all fail fast.
- We can’t tell exactly where the error was raised.
- It’s not easy to do error recovery.

## Exercise 4.5.4: Abstracting

A possible implementation for `validateAdult`

is the following:

If `age`

is greater than or equal to 18, we summon an `Applicative`

for `F`

(which we must have in scope due to `MonadError`

) and lift the `age`

to `F`

. If
`age`

is less than 18, we use the `MonadError`

instance we have in scope to lift
an `IllegalArgumentException`

to `F`

.

## Exercise 4.6.5: Safer Folding using Eval

One way to make the naive implementation of `foldRight`

stack safe using `Eval`

is the following:

We defer the call to the recursive step and then map over it to apply `fn`

, all
within the context of `Eval`

.

## Exercise 4.7.3: Show Your Working

A possible rewrite of `factorial`

so that it captures the log messages in a
`Writer`

is the following:

We can show that this allows us to reliably separate the logs for concurrent
computations because we have the logs for each instance captured in each
`Writer`

instance:

## Exercise 4.8.3: Hacking on Readers

To create a type alias for a `Reader`

that consumes a `Db`

we want to fix the
first type parameter of `Reader`

to `Db`

, while still leaving the result type as
a type parameter:

The `findUsername`

and `checkPassword`

functions can be implemented as follows:

The `checkLogin`

method can be implemented as follows:

We are making use of the `findUsername`

and `checkPassword`

methods. There are
two scenarios in which `checkLogin`

can return a `false`

for a given `Db`

: when
the username doesn’t exist and when the password doesn’t match.

## Exercise 4.9.3: Post-Order Calculator

A possible implementation of `evalOne`

with no proper error handling is the
following:

We’re not told which operands to support, so I assumed at least `+`

, `*`

, `-`

and `/`

.

For the `evalAll`

implementation, we’re not told what to do in case the input is
empty. I assumed it would be OK to just have an exception thrown (since that was
the case before), and relied on `reduce`

over the `evalOne`

calls:

The `evalInput`

method can rely on a call to `evalAll`

after splitting the
input by whitespaces:

## Exercise 4.10.1: Branching out Further with Monads

One implementation of `Monad`

for `Tree`

is the following:

However, `tailRecM`

isn’t tail-recursive. We can make it tail-recursive by
making the recursion explicit in the heap. In this case, we’re using two mutable
stacks: one of open nodes to visit and one of already visited nodes. On that
stack, we use `None`

to signal a non-leaf node and a `Some`

to signal a leaf
node.