주요글: 도커 시작하기
반응형

마틴 오더스키 교수님이 코세라에서 진행중인 Functional Programming Principles in Scala 강의(https://www.coursera.org/learn/progfun1)의 3주차 요약.


* 함수형을 잘 모르는 상태에서 요약한 것이므로 내용에 오류가 존재할 수 있음

* 3주차는 주로 클래스와 객체에 대한 내용으로 비교적 익숙했음


클래스 계층


추상 클래스는 구현이 없는 멤버를 포함할 수 있다. 구현이 없으므로 new로 추상 클래스의 인스턴스를 생성할 수 없다.


abstract class IntSet {

  def incl(x: Int): IntSet

  def contains(x: Int): Boolean

}


IntSet 클래스를 확장(extend)한 두 클래스-Empty, NonEmpty-는 다음과 같이 구현 가능하다.


class Empty extends IntSet {

  def contains(x: Int): Boolean = false

  def incl(x: Int): IntSet = new NonEmpty(x, new Empty, new Empty)

}

class NonEmpty(elem: Int, left: IntSet, right: IntSet) extends IntSet {

  def contains(x: Int): Boolean = 

    if (x < elem) left contains x else if (x > elem) right contains x else true

 

  def incl(x:Int): IntSet = 

    if (x < elem) new NonEmpty(elem, left incl x, right)

    else if (x > elem) new NonEmpty(elem, left, right incl x)

    else this

}


여기서 Empty와 NonEmpty는 IntSet 타입을 따르며(conform), IntSet 타입이 필요한 곳에 이 두 타입의 객체를 사용할 수 있다.


IntSet을 Empty와 NonEmpty의 상위클래스(superclass)라고 하며, Empty와 NonEmpty를 IntSet의 하위클래스(subclass)라고 한다.


상위 클래스를 지정하지 않으면 java.lang.Object 클래스를 상위 클래스로 가정한다. C 클래스의 직/간접 상위클래스를 베이스 클래스(base class)라고 한다. NonEmpty 클래스의 경우 IntSet과 Object가 베이스 클래스가 된다.


오버라이드를 사용하면 상위 클래스에 정의된 비추상 멤버를 재정의할 수 있다. 다음 코드에서 Sub 클래스의 foo 멤버는 Base 클래스의 foo 멤버를 재정의하고 있다.


abstract class Base {

  def foo = 1

  def bar: Int

}

class Sub extends Base {

  override def foo = 2

  def bar = 3

}


오브젝트


스칼라는 한 개의 인스턴스만 갖는 타입인 오브젝트를 지원한다. 예를 들어, NonEmpty는 한 개 인스턴스가 존재하면 되는데 다음과 같이 오브젝트 정의를 사용해서 NonEmpty를 싱글톤으로 정의할 수 있다.


object Empty extends IntSet {

  def contains(x: Int): Boolean = false

  def incl(x: Int): IntSet = new NonEmpty(x, Empty, Empty)

}


동적 바인딩(dynamic binding)


스칼라를 포함한 객체 지향 언어는 동적 바인딩을 구현한다. 동적 바인딩은 메서드를 호출할 때 메서드를 포함한 객체의 런타임 타입에 의존한다는 것을 의미한다.


치환 모델로 동적 바인딩의 계산 과정을 풀면 다음과 같다.


(new NonEmpty(7, Empty, Empty)) contains 7

-> [7/elem][7/x][new NonEmpty(7, Empty, Empty)/this] 

      if (x < elem) this.left contains x 

      else if (x > elem) this.right contains x else true

-> if (7 < elem) new NonEmpty(7, Empty, Empty).left contains 

    else if (7 > 7) new NonEmpty(7, Empty, Empty).right contains 7 else true

-> true


패키지와 임포트


자바처럼 패키지를 이용해서 클래스와 오브젝트를 구성한다. 패키지를 포함한 fully qualified 이름으로 클래스나 오브젝트를 참조할 수 있다.


import를 이용해서 단순 이름으로 사용할 수 있다. scala, java.lang, scala.Predef 오브젝트의 모든 멤버는 자동으로 임포트한다.


트레잇(trait)


스칼라의 클래스는 한 개의 상위클래스만 가질 수 있다. 다중 상속이 필요한 경우 트레잇을 사용할 수 있다. 트레잇은 추상 클래스처럼 추상 멤버와 구현을 가진 멤버를 선언할 수 있다. 


trait Planar {

  def height: Int

  def width: Int

  def surfce = height * width

}


클래스, 오브젝트, 트레잇은 최대 한 개의 클래스를 상속할 수 있지만, 트레잇은 여러 개를 상속할 수 있다.


class Square extends Shape with Planar with Movable ...


트레잇은 필드와 메서드 구현을 가질 수 있기 때문에 자바 인터페이스보다 더 강력하다. 클래스가 파라미터를 가질 수 있는 것과 달리 트레잇은 가질 수 없다.


스칼라 클래스 계층

  • Any: 모든 타입의 베이스 타입이다. ==, !=, equals, hashCode, toString 메서드를 정의한다.
  • AnyRef: 모든 레퍼런스 타입의 기반 타입이다. java.lang.Object에 해당한다. scala.List, scala.Seq 등이 속한다.
  • AnyVal: 모든 원시 타입의 기반 타입니다. (scala.Int, scala.Boolean 등이 속한다.)
  • Null: 레퍼런스 타입은 값으로 null을 가질 수 있다. null은 Null 타입 값으로 Null 타입은 Object를 상속한 모든 클래스의 하위타입이다.
  • Nothing: 모든 타입의 하위 타입으로 스칼라 타입 계층의 최하단에 위치한다.

다형(polymorphism)


다형은 함수 타입이 여러 폼(form)이 된다는 것을 의미한다. 이는 프로그래밍에서 다음을 뜻한다.

  • 함수를 여러 타입의 인자에 적용할 수 있거나 -> 지네릭: 함수나 클래스의 인스턴스를 타입 파라미터로 생성
  • 타입이 많은 타입의 인스턴스를 가질 수 있다 -> 하위타입: 하위클래스의 인스턴스를 베이스 클래스(형태)로 전달
예)
trait List[T]
class Cons[T](val head: T, val tail: List[T]) extends List[T]
class Nil[T] extends List[T]


상속을 통한 다형 : Nil 인스턴스를 List가 필요한 곳에 전달할 수 있다 -> new Cons(10, Nil)

타입파라미터를 통한 다형 : Cons를 여러 타입에 적용할 수 있다. Cons[User](u1, Nil), Cons[Member](m1, Nil)


+ Recent posts