Skip to content

2016 08 09 cbk

baekkyu cho edited this page Aug 8, 2016 · 16 revisions

2장 스칼라로 함수형 프로그래밍 시작하기

<요약>
- 꼬리재귀함수를 이용하여 loop를 작성하는 방법
- 고차함수 소개
- 다형적 고차함수의 예

2.1 스칼라 언어의 소개

// 주석
/* 주석 */
/** 주석 */
object MyModule {    //object 키워드는 singleton 형식을 만든다. (java의 static과 비슷)
  def abs(n: Int): Int =    // 정수 하나를 받고, 절댓값을 돌려주는 순수함수
    if (n < 0) -n           // 등호(=) 기준으로 왼쪽을 좌변 또는 서명(signature), 오른쪽을 우변 또는 정의(definition)이라고 부른다.
    else n                  // return 키워드는 없음. 우변의 평가결과가 곧 메서드의 반환값이다.

  private def formatAbs(x: Int) = {    // return형식은 타입추론이 가능하다.
    val msg = "The absolute value of %d is %d"
    msg.format(x, abs(x))
  }

  // java의 main메서드와 동일한 기능, 부수효과가 발생하기 때문에 절차(procedure), 불순함수(impure funtion)라고 부른다.
  def main(args: Array[String]): Unit =    //Unit은 java, c의 void와 같은 목적
    println(formatAbs(-42))
}

2.2 프로그램의 실행

  • 일반적으론 스칼라용 빌드도구인 sbt를 이용하는 것이 좋다.
  • 간단한 방법은 스칼라 컴파일러를 이용하는 것이다.
// 컴파일 -> .class파일이 생성된다 (JVM에서 실행될 수 있는 java byte code로 컴파일됨)
> scalac MyModule

// 컴파일된 파일을 스칼라를 이용하여 실행
> scala MyModule
The absolute value of -42 is 42

// 직접 소스파일을 지정하여 스칼라 해석기(interpreter)로 실행하는것도 가능.
> scala MyModule.scala
The absolute value of -42 is 42

// 대화식모드 REPL(read-evaluate-print loop)을 이용하는 방법.
scala> :load MyModule.scala
Loading MyModule.scala...
defined object MyModule

scala> MyModule.abs(-42)
res0: Int = 42

2.3 모듈, 객체, 이름공간

  • 스칼라의 모든값은 **객체(object)**이다, 객체는 0개 또는 하나이상의 구성원(member)를 가질 수 있다.
  • 2 + 1 같은 표현식도 object의 member를 호출하는 것이다. 해당표현식은 2.+(1)에 대한 구문적 겉치레(syntatic sugar)일 뿐이다.
  • 스칼라에서는 연산자(operator)라는 개념이 존재하지 않는다.
  • 인수가 하나인 메서드(method)는 마침표와 괄호를 생략한 중위(infix)표기법으로 호출이 가능하다.
  • MyModule은 abs가 속한 이름공간(namespace) 이다.
  • 자신의 member들에게 namespace를 제공해주는 것이 주된목적인 object를 흔히 **모듈(module)**이라고 부른다.

2.4 고차함수: 함수를 함수에 전달

  • 순수한 함수적 프로그램을 작성할 때에는 다른 함수를 인수로 받는 함수를 작성하는 것이 유용한 경우가 많다. 이런 함수를 고차함수(higher-order function)라고 부른다.

2.4.1 잠깐 곁가지: 함수적으로 루프 작성하기

  • 계승을 구하는 factorial 함수 작성
  // loop를 함수적으로(loop 변수의 변이없이) 작성하는 방법은 재귀함수(recursive function)를 이용하는 것이다.
  def factorial(n: Int): Int = {
    @annotation.tailrec    // 꼬리호출제거여부를 확인해주는 annotation
    def go(n: Int, acc: Int): Int =    //지역정의(local definition)
      if (n <= 0) acc
      else go(n-1, n*acc)

    go(n, 1)
  }
  • 재귀함수는 stackoverflow를 발생시킬 위험이 있다.
  • 스칼라 컴파일러는 자기재귀(self-recursion)를 검출해서, 재귀호출이 꼬리위치(tail position)에서 일어난다면 바이트코드를 생성할 때, while loop와 같은 형태로 변환시켜 준다.

2.4.2 첫 번째 고차 함수 작성

  • factorial 함수를 추가함

Clone this wiki locally