Remove monad transformer return types from algebras
Ghurtchu opened this issue · 1 comments
Ghurtchu commented
Monad transformer return types such as EitherT
or OptionT
in algebra definitions is a kind of an anti-pattern, it is better to have F[Option[A]]
or F[Either[A, B]]
there.
If you would like to see the alternative approach then I can open a small PR which demonstrates the positive changes but I think I will need some kind of access to do that, thank you.
Ghurtchu commented
alternative algebra:
trait PetValidationAlgebra[F[_]] {
/* Fails with a PetAlreadyExistsError */
def doesNotExist(pet: Pet): F[Either[PetAlreadyExistsError, Unit]]
/* Fails with a PetNotFoundError if the pet id does not exist or if it is none */
def exists(petId: Option[Long]): F[Either[PetNotFoundError.type, Unit]]
}
alternative interpreter:
package io.github.pauljamescleary.petstore.domain
package pets
import cats.Applicative
import cats.syntax.functor._
import cats.syntax.either._
import cats.syntax.applicative._
class PetValidationInterpreter[F[_]: Applicative](repository: PetRepositoryAlgebra[F])
extends PetValidationAlgebra[F] {
override def doesNotExist(pet: Pet): F[Either[PetAlreadyExistsError, Unit]] =
repository.findByNameAndCategory(pet.name, pet.category).map { pets =>
val petNames = pets.map(_.bio)
Either.cond(!petNames.contains(pet.name), (), PetAlreadyExistsError(pet))
}
override def exists(petId: Option[Long]): F[Either[PetNotFoundError.type, Unit]] = {
petId.fold(PetNotFoundError.asLeft[Unit].pure[F]) { id =>
repository.get(id).map { maybePet =>
Either.cond(maybePet.isDefined, (), PetNotFoundError)
}
}
}
}
object PetValidationInterpreter {
def apply[F[_]: Applicative](repository: PetRepositoryAlgebra[F]) =
new PetValidationInterpreter[F](repository)
}