NMP-Study / FunctionalProgrammingInScala

2 stars 0 forks source link

[함수형 프로그래밍] Chapter4.예외를 이용하지 않은 오류 처리 #11

Closed duckcalf closed 5 years ago

enochyeon commented 5 years ago

목표

4.1 예외의 장단점

목록 4.1

// 참조 투명성 테스트 코드
def failingFn(i: Int): Int = {
  val y: Int = throw new Exception("fail!")
  try {
    val x = 42 + 5
    x + y
  }
  catch { case e: Exception => 43 }
}

def failingFn2(i: Int): Int = {
  try {
    val x = 42 + 5
    x + ((throw new Exception("fail!")): Int)
  }
  catch { case e: Exception => 43 }
}

println(failingFn(12))
//println(failingFn2(12))

https://scalafiddle.io/sf/YbyNapO/0

참조 투명성

표현식 비고
참조에 투명 문맥에 의존하지 않으며 지역적으로 추론 가능
참조에 투명하지 않음 문맥에 의존적이고 전역적 추론 필요

예외의 주된 문제

4.2 예외의 가능한 대안들

대안1. 별도의 값 반환

def mean(xs: Seq[Double]): Double = 
    if (xs.isEmpty)
        throw new ArithmeticException("mean of empty list!")
    else
        xs.sum / xs.length

대안2. 행동을 알려주는 인수 전달

def mean_1(xs: IndexedSeq[Double], onEmpry: Double): Double = 
    if (xs.isEmpty)
        onEmpty
    else
        xs.sum / xs.length

4.3 Option 자료 형식

sealed trait Option[+A]
case class Some[+A](get: A) extends Option[A]
case object None extends Option[Nothing]
def mean_1(xs: Seq[Double]): Option[Double] = 
    if (xs.isEmpty)
        None
    else
        Some(xs.sum / xs.length)

4.3.1 Option의 사용 패턴

사용 예시

Option에 대한 기본적인 함수를

trait Option[+A] {
    def map[B](f: A => B): Option[B]
    def flatMap[B](f: A => Option[B]): Option[B]
    def getOrElse[B >: A](default: => B): B
    def orElse[B >: A](ob: => Option[B]): Option[B]
    def filter(f: A => Boolean): Option[A]
}

기본적인 Option 참수들의 용례

정리

4.3.2 예외 지향적 API의 Option 합성과 승급, 감싸기

def lift[A,B](f: A => B): Option[A] => Option[B] = _ map f

var abs0: Option[Double] => Option[Double] = lift(math.abs)

for-comprehension(함축)

def map2[A,B,C](a: Option[A], b: Option[B])(f: (A, B) => C): Option[C] =
    a flatMap (aa => 
        b map (bb =>
            f(aa, bb)))

def map2[A,B,C](a: Option[A], b: Option[B])(f: (A, B) => C): Option[C] =
    for {
        aa <- a
        bb <- b
    } yield f(aa, bb)

4.4 Either 자료 형식

sealed trait Either[+E, +A]
case class Left[+E](value: E) extends Either[E, Nothing]
case class Right[+A](value: A) extends Either[Nothing, A]
def mean(xs: IndexedSeq[Double]): Either[String, Double] =
    if (xs.isEmpty)
        Left("mean of empty list!")
    else
        Right(xs.sum / xs.length)

def safeDiv(x: Int, y: Int): Either[Exception, Int] =
    try Right(x / y)
    catch {case e: Exception => Left(e)}

def Try[A](a: => A):Either[Exception, A] =
    try Right(a)
    catch {case e: Exception => Left(e)}

def parseInsuranceRateQuote(
    age: String, numberOfSpeedingTickets: String): Either[Exception, Double] =
    for {
        a <- Try {age.toInt}
        tickets <- Try {numberOfSpeedingTickets.toInt}
    } yield insuranceRateQuote(a, tickets)

4.5 요약