본문 바로가기

프로그래밍

coursera 스칼라 1주차

스칼라 스터디 1주차

1.1 프로그래밍 패러다임

  • 절차지향 (IMPERATIVE)

    할당과 제어문을 통해 status update

  • 함수형 (FUNCTIONAL)
  • 논리형 (LOGIC)

    ex) prolog


순수 절차지향 추상화된 데이터 구조에 대한 작업을 어렵게 만든다.
-> 해결책 : THEORY

Theory란?

원소연산의 정의

ex) group theory, category theory, field theory

NO MUTATION!!!


Theory-like programming

  • 연산의 정의
  • mutation 최소화
  • 연산을 합성함수로…

Functional Programming

엄밀한 함수형 프로그래밍 : 변수, 할당, 제어문 없는 프로그래밍
완화된 함수형 프로그래밍 : 함수에 집중하는 프로그래밍(?)

Scala는 완화된 함수형 프로그래밍

함수형 언어에서는 함수가 first-class citizen
=> 합성함수를 만들 수 있다는 뜻.

History

시기 언어
1959 Lisp
1975-77 ML, FP, Scheme
1978 Smalltalk
1986 Standard ML
1990 Haskell, Erlang
1999 XSLT
2000 OCaml
2003 Scala, XQuery
2005 F#
2007 Clojure

1.2 프로그래밍의 원소

스칼라 연산 이밸류에이션 과정

  1. 우선순위 연산자 선택
  2. 연산자에 적용할 피연산자 왼쪽, 오른쪽 순으로 evaluate
  3. 피연산자에 연산자 적용
  • 이름의 경우, 이름의 오른쪽의 정의로 evaluate. value를 return할 때까지 evaluate.

스칼라 정의문

def power(x: Double, y: Int): Double = ... //return type은 optional

def size = 2;

스칼라 함수 이밸류에이션 과정

  1. 함수 인자를 왼쪽부터 오른쪽으로 evaluate
  2. 함수를 그 이름의 오른쪽의 정의로 대체하면서
  3. evaluate한 인자들을 paramter에 대입함.
sumOfSquares(3, 2+2)
sumOfSquares(3, 4)
square(3) + square(4)
3 * 3 + square(4)
9 + square(4)
9 + 4 * 4
9 + 16
25

이밸류에이션 전략
call-by-value : 인자 evaluate -> 함수 이름을 대체

argument 연산을 한번만 수행한다.

call-by-name : 함수 이름을 대체 -> 인자 evaluate

argument가 함수 내부에서 사용되지 않는다면 eval을 하지 않는다.

위에 예제는 call-by-value.
call by name은 다음과 같다.

sumOfSquares(3, 2+2)
square(3) + square(2+2)
3 * 3 + square(2+2)
9 + square(2+2)
9 + (2+2) * (2+2)
9 + 4 * (2+2)
9 + 4 * 4
25

1.3 이밸류에이션의 전략과 종료

이밸류에이션은 value를 return 하면서 종료된다. 이밸류에이션은 항상 종료될까?

def loop :Int = loop;

함수 evaluation이 CBV 전략으로 종료되면 CBN으로도 종료된다.
역은 항상 성립하지 않는다.

def first(x: Int, y: Int) = x;

first(1, loop); // CBV에서는 종료되지 않는다.

1.4 Conditional and Value Definition

스칼라의 조건문은 statement가 아니라 evaluation에만 사용가능하다.

def abs(x: Int) = if (x >= 0) x else -x

boolean reduction rule

!true —> false
!false —> true
true && e —> e
false && e —> false
true || e —> true
false || e —> e


Value Definition

def는 사용될 때 evaluate, val은 정의할 때 evaluate.

def and(x: Boolean, y: Boolean) = if (x) y else false

def and(x: Boolean, y: => Boolean) = if (x) y else false //y를 call-by-name으로 호출

1.5 제곱근을 구하기 위한 뉴턴 메써드

  def abs(x: Double) = if (x < 0) -x else x         //> abs: (x: Double)Double

  def sqrtIter(guess: Double, x: Double): Double =
  if (isGoodEnough(guess, x)) guess
  else sqrtIter(improve(guess, x), x)             //> sqrtIter: (guess: Double, x: Double)Double

  def isGoodEnough(guess: Double, x: Double) =
  abs(guess * guess - x) / x < 0.001              //> isGoodEnough: (guess: Double, x: Double)Boolean

  def improve(guess: Double , x: Double) =
  (guess + x / guess) / 2                         //> improve: (guess: Double, x: Double)Double

  def sqrt(x : Double) = sqrtIter(1.0 , x)        //> sqrt: (x: Double)Double

  sqrt(2)                                         //> res0: Double = 1.4142156862745097
  sqrt(4)                                         //> res1: Double = 2.000609756097561
  sqrt(1e-6)                                      //> res2: Double = 0.0010000001533016628
  sqrt(1e60)                                      //> res3: Double = 1.0000788456669446E30

1.6 블락과 렉시컬 스코핑

nested scope를 활용한 뉴턴 메써드 rewrite

def sqrt(x: Double) = {
    def sqrtIter(guess: Double, x: Double): Double =
        if (isGoodEnough(guess, x)) guess
        else sqrtIter(improve(guess, x), x)

    def improve(guess: Double, x: Double) =
        (guess + x / guess) / 2

    def isGoodEnough(guess: Double, x: Double) =
        abs(square(guess) - x) < 0.001
    sqrtIter(1.0, x)
}

Blocks in Scala

  • {}를 사용해 블락을 지정.
  • definition 과 expression에 대한 sequence
  • 마지막에 오는 expression이 return
  • expression이 올 수 있는 모든 곳에 블락 지정 가능
  • 블락 외부에서 내부 접근 불가능, 내부에서는 naming space가 겹치지 않을 때만 외부 접근 가능.

세미콜론
Optional

1.7 Tail Recursion

function이 마지막에 자기 자신을 호출하면 tail recursion 이라고 한다. tail recursive optimization 이 구현되어 있는 compiler나 interpreter에서는 이런 tail recursive 함수를 iteration으로 변경해서 stackoverflow를 막아준다.

scala에서는 자기 자신을 호출하는 함수만 최적화를 해준다. @tailrec을 붙여서 강제로 최적화 구현하게 가능.

 def factorial(n: Int) :Int=
           if (n == 1 ) 1
           else n * factorial(n-1)



        def factorial(n: Int)
          return f(n , n-1);


def f(a : Int, b: Int) =
    if (b == 0)
          a
    else
        f((a * b-1), b-1)
}

Factorial(5)
= f(5,4)
=f(5*4,3)
=f(5*4*3,2)
=f(5*4*3*2,1)
=f(5*4*3*2*1,0)
=5*4*3*2*1