본문 바로가기

학교 공부/프로그래밍원리

1122 Stacking with Type Classes

Part 3 - 53쪽 / 전체 슬라이드 기준 264

 

205쪽에서 다뤘었음 

Stacking with traits

 

 

Base

trait Stack[A] {
   def get() : (A,Stack[A])
   def put(x:A) : Stack[A]
}

 

Core

class BasicIntStack protected (xs: List[Int]) extends Stack[Int] {

    override val toString = "Stack:" + xs.toString 
    def this() = this(Nil)
    protected def mkStack(xs: List[Int]): Stack[Int] = new BasicIntStack(xs)
    def get(): (Int,Stack[Int]) = (xs.head, mkStack(xs.tail)) 
    def put(x: Int): Stack[Int] = mkStack(x :: xs)
}

 

val s0 = new BasicIntStack 

val s1 = s0.put(3)
val s2 = s1.put(-2)
val s3 = s2.put(4)

val (v1,s4) = s3.get()
val (v2,s5) = s4.get()

 

 

custom

trait Doubling extends Stack[Int] {
    abstract override def put(x: Int): Stack[Int] = super.put(2 * x)
}
trait Incrementing extends Stack[Int] {
    abstract override def put(x: Int): Stack[Int] = super.put(x + 1)
}
trait Filtering extends Stack[Int] {
    abstract override def put(x: Int): Stack[Int] =
      if (x >= 0) super.put(x) 
      else this 
}

 

...

 

multiple inheritance 로 했었음

extends ~ with ~ with ~ with

 

 

 

 

 

 

 

 

 

 

 

 

 

오늘 수업 시간에 다룰 내용은

Stacking with Type classes

 

Base 구현

trait Stack[S,A]{
    def empty : S
    def get(s:S):(A,S)
    def put(s:S)(x:A):S
}

//Int stack으로 하나 구현

def testStack[S](implicit stk:Stack[S,Int])={
    val s0 = stk.empty
    val s1 = stk.put(s0)(3) //s0에 3을 넣어라
    val s2 = stk.put(s1)(-2)
    val s3 = stk.put(s2)(4)
    val (v1,s4) = stk.get(s3) //tuple을 이용해 여러개의 변수에 동시에 값 넣기
    val (v2,s5) = stk.get(s4)
    
    (v1,v2)

}

 

core 구현 (Int Stack으로 구현)

implicit def StackListInt:Stack[List[Int],Int]= new Stack[List[Int],Int] {
   val empty = List()
   def get(s:List[Int]) = (s.head, s.tail)
   def put(s:List[Int])(x:Int) = x :: s
}

 

Modifying Traits

토핑 올리기

스택을 받아서 스택을 리턴하는 함수를 구현하자.

def IntStackWithPut[S](parent:Stack[S,Int], newPut:(S,Int)=>S):Stack[S,Int]= new Stack[S,Int]{
    def empty = parent.empty
    def get(s:S) = parent.get(s)
    def put(s:S)(x:Int) = newPut(s,x)
}

def Doubling[S] (parents:Stack[S,Int]):Stack[S,Int] = 
	IntStackWithPut(parent,(s,x)=>parent.put(s)(2*x))
    
def Incrementing[S] (parents:Stack[S,Int]):Stack[S,Int] = 
	IntStackWithPut(parent,(s,x)=>parent.put(s)(x+1))
   
def Filterint[S](parent:Stack[S,Int]):Stack[S,Int]=
	IntStackWithPut(parent,(s,x)=>if(x>=0) parent.put(s)(x) else s)

코드 재사용이 잘 되고 있는 것을 확인할 수 있다.

 

 

코드 실행 결과)

testStack(Filtering(Incrementing(Doubling(StackListInt)))

res 0 : (10,8) 

 

testStack(Doubling(Doubling(StackListInt)))

res 1:(16,-8)

 

 

 

==> 내가 쓰고 싶은 함수를 인자로 받아서 조금 수정해가면서 reuse 하는 것이 composition

상속은 코드 관리가 어려움. 상위 코드를 조금 수정하는 순간 뒤죽박죽이 되니까

 

OOP는 문제가 많고 그 대안은 Type Class임.

추상화하는 것(interface)과, 기존 코드의 재활용성(Composition) 관점에서 자연스럽게 지원하고 있는 것은 타입클래스임.

 

 

 

 

 

 

++ Implementaion : Sorted Stack

def sortedStqackList : Stack[List[Int],Int] = new Stack[List[Int],Int] {
    def empty = List()
    def get(s:List[Int]):(Int,List[Int]) = (s.head, s.tail) 
    def put(s:List[Int](x:Int):List[Int]={
    	def go(l:List[Int]):List[Int] = l match {
            case Nil => x::Nil
            case hd::tl => if(x<=hd) x::l else hd::go(tl)
        }
        go(s)
    }
}