Я использую cats-effect
для приостановки побочных эффектов и столкнулся с трудностями при реализации чистых функций, избегая подверженных ошибкам Throwable
s.Проблема в том, что cats.effect.Sync[F[_]]
extends Bracket[F, Throwable]
.
sealed trait Err
final case class FileExistError(path: String) extends Err
case object UnknownError extends Err
final case class FileExistThrowable(path: String, cause: Throwable) extends Throwable
final class File[F[_]: Sync]{
def rename(from: String, to: String): F[Unit] =
implicitly[Sync[F]] delay {
try{
Files.move(Paths.get(from), Paths.get(to))
} catch {
case e: FileAlreadyExistsException =>
throw FileExistThrowable(to, e)
case e => throw e
}
}
}
В случае, например, cats.effect.IO
я могу преобразовать эффекты с помощью NaturalTransform следующим образом:
implicit val naturalTransform: IO ~> EitherT[IO, Err, ?] =
new ~>[IO, EitherT[IO, Err, ?]] {
override def apply[A](fa: IO[A]): EitherT[IO, Err, A] =
EitherT(
fa.attempt map { e =>
e.left map {
case FileExistsThrowable(path, cause) =>
FileExistsError(path)
case NonFatal(e) =>
UnknownError
}
}
)
}
К сожалению, это кажется ненадежными ошибка склонна.В эффективной реализации мы можем бросить любой тип броска, который будет описан как UnknownError
.
Это не кажется более надежным, чем просто использование Throwable
s с try-catch
.Кто-нибудь может предложить лучшую / более безопасную технику для устранения ошибок?