scala/scala3

Either using cats and ox

wefree 2024. 4. 4. 19:06

catsox 를 활용해 Either 를 강력하게 사용하기

 

Cats Either Helper

  • .asRight .asLeft
  • .leftMap .map
  • Either.catchNonFatal,  Either.catchOnly
  • Either.fromTry, Either.fromOption

Ox Either Helper

 

코드

 libraryDependencies += "org.typelevel" %% "cats-core" % "2.10.0",
 libraryDependencies += "com.softwaremill.ox" %% "core" % "0.1.0"
import cats.*
import cats.syntax.all.*

import scala.util.{Failure, Try}

enum AppError(val code: Int, val message: String, val detail: String) extends Throwable {
  case BadRequest(override val detail: String) extends AppError(400, "bad request", detail)
  case ServerError extends AppError(500, "server error", "")
}

@main def Main(): Unit = {
  val e2: Either[Throwable, Int] = Either.catchNonFatal(2)
  val e3: Either[ArithmeticException, Int] = Either.catchOnly[ArithmeticException](1 / 0)
  val e4: Either[AppError, Int] = Either
    .fromTry[Int](Failure(Exception("something wrong")))
    .leftMap(e => AppError.BadRequest(e.getMessage))
  //  val t4: Try[Int] = e4.toTry

  import ox.either
  import ox.either.{ok, fail}

  val result: Either[Unit | Throwable, Int] = either { // o5 때문에 Left 로 Unit 이 추가됨
    val e1: Either[AppError, Int] = 4.asRight[AppError]
    val v1: Int = e1.ok()

    val o5: Option[Int] = none[Int]
    val v2345: Int = v1 match {
      case 2 => e2.ok()
      case 3 => e3.ok()
      case 4 => e4.ok()
      case 5 => o5.ok()  // Option 을 Either 로 변환하지 않더라도 자연스럽게 composing 될 수 있다 !!!
      case _ => AppError.ServerError.fail() // 한번에 탈출(?) 해 최종 결과 either Left 로 직행할 수 있다.
    }

    v1 + v2345
  }

  result match {
    case Right(v)           => println(s"success: $v") // when v1 == 2
    case Left(e: AppError)  => println(s"error: code=${e.code}, message=${e.message}, detail=${e.detail}") // when v1 == 4
    case Left(e: Throwable) => println(s"error: unknown, ${e.getMessage}") // when v1 == 3
    case Left(())           => println(s"error: option empty") // when v1 == 5
  }

  println(result)
}

 

 

scala.util.control.Exception.catching

https://www.scala-lang.org/api/current/scala/util/control/Exception$.html

  import scala.util.control.Exception._
  import java.net._

  val s = "https://www.scala-lang.org/"
  val x2: Either[Throwable,URL] = 
    catching(classOf[MalformedURLException], classOf[NullPointerException]).either(new URL(s))