본문 바로가기

Language/Scala

[Scala] Functional data structures

반응형

3.1 함수적 자료구조의 정의

 

 

예를 들어 순수 함수 +에서, 3 + 4을 수행했을 때 3이나 4의 값이 변경되는 일 없이 새로운 값 7이 생성된다. 함수적 자료구조로 정의된 List에 새로운 항목을 추가해도 기존 List가 변경되지는 않는다.


package fpinscala.datastructures

sealed trait List[+A] // A 타입 List
case object Nil extends List[Nothing] // empty list 생성자
case class Cons[+A](head: A, tail: List[A]) extends List[A] // nonempty lists를 나타내는 또 다른 생성자. 
// tail은 또 다른 List[A]로 Nil일 수도 Cons일 수도 있다.

object List { // List: companion 객체. lists 생성과 조작을 위한 함수 포함.
  def sum(ints: List[Int]): Int = ints match { // pattern matching을 이용하여 list의 정수의 합을 구하는 함수
    case Nil => 0 // empty list의 합은 0.
    case Cons(x,xs) => x + sum(xs) // x로 시작하는 list의 합은 x + list 나머지 부분의 합.
  }

  def product(ds: List[Double]): Double = ds match {
    case Nil => 1.0
    case Cons(0.0, _) => 0.0
    case Cons(x,xs) => x * product(xs)
  }

  def apply[A](as: A*): List[A] = // 가변인수 함수 구문
    if (as.isEmpty) Nil
    else Cons(as.head, apply(as.tail: _*))
}

 

  • 특질(trait)은 일부 메서드의 구현을 담을 수 있는 추상 인터페이스로, sealed는 이 특질의 모든 구현이 반드시 같은 파일 안에 선언되어 있어야 함을 뜻한다.
    일반적으로 자료 형식을 도입할 때, trait키워드를 사용한다. trait키워드를 이용하여 List라는 특질을 정의한다.
    List는 sealed trait 대신 abstract class를 사용해도 된다. ()
  • Nil과 Cons는 List의 두 가지 구현, 즉 두 가지 자료 생성자(data constructor)이다. List가 취할 수 있는 두 가지 형태 즉, Nil로 표기되는 빈 목록일 수 있고, Con(Contructor)로 표기되는 비지 않은 목록일 수 있다.

  • 형식 매개 변수 A에 있는 +는 공변(covariant)을 뜻한다.
    함수를 다형적으로 만들 수 있듯이, 자료 구조도 다형적으로 만들 수 있다. sealed trait list 다음에 형식 매개변수 [+A]를 두고 Cons 생성자 안에서 그 A 매개변수를 사용함으로써 목록에 담긴 요소들의 형식에 대해 다형성이 적용되는 List 자료 구조가 만들어진다. 그러면 하나의 동일한 정의로 Int 요소들의 목록 (List[Int]로 표기), Double 요소들의 목록(List[Double]) 등을 사용할 수 있다. 변수 A에 있는 +는 공변을 뜻한다.
trait List[+A] 선언에서 A 앞의 +는 A가 List의 공변(covariant) 매개 변수임을 뜻하는 가변 지정자(variance annotation; 가변 주해)로서, 양의(positive) 매개변수라고 하기도 한다.

예를 들어, Dog가 Animal의 하위형식이면 List[Dog]가 List[Animal]의 하위형식으로 간주된다.
case object Nil extends List[Nothing]에서 Nothing은 모든 형식의 하위형식이고 A가 공변이므로 Nil은 List[Int], List[Double] 등 어떤 형식으로도 간주될 수 있다.

 

3.2 패턴 부합

 

동반 객체(companion object)

class나 trait와 동일한 이름을 사용하는 객체로서, 동반되는 class나 trait의 private 필드나 메서드에 접근할 수 있다.

패턴 부합(pattern matching)

패턴 부합은 표현식의 구조를 따라 내려가는 switch문과 비슷하며 표현식(대상(target) 또는 검사자(scrutinee))으로 시작하여 키워드 match가 오고 일련의 case가 {}으로 감싸인 형태이다. {}에는 좌변에 패턴, 우변에 결과가 서술된다.


  def sum(ints: List[Int]): Int = ints match { // pattern matching을 이용하여 list의 정수의 합을 구하는 함수
    case Nil => 0 // empty list의 합은 0.
    case Cons(x,xs) => x + sum(xs) // x로 시작하는 list의 합은 x + list 나머지 부분의 합.
  }

  def product(ds: List[Double]): Double = ds match {
    case Nil => 1.0
    case Cons(0.0, _) => 0.0
    case Cons(x,xs) => x * product(xs)
  }

 

반응형

'Language > Scala' 카테고리의 다른 글

[Scala] State  (0) 2019.11.10
[Scala] Data Structures  (0) 2019.11.10
[Scala] Getting started with functional programming in scala  (0) 2019.10.28
[Scala] FP의 두 가지 개념  (0) 2019.10.12
[Scala] What is functional programming?  (0) 2019.10.04