본문 바로가기

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

11/16 Type Classes With Multiple Parameters & Higher-kind

http://jaynewho.com/post/3

http://jaynewho.com/post/4

testList[List[Int]]

 

implicit def listIter[A] : Iter[List[A], A] = 
  new Iter[List[A],A] {
	def getValue(a: List[A]) = a.headOption
	def getNext(a: List[A]) = a.tail }
    
implicit def listIF[A] : ListIF[List[A],A] = 
  new ListIF[List[A],A] {
	def empty: List[A] = Nil
	def head(l: List[A]) = l.headOption
	def tail(l: List[A]) = l.tail
	def cons(a: A, l: List[A]) = a :: l
	def append(l1: List[A], l2: List[A]) = l1 ::: l2
}

 

 

 

Tree 예제

trait ListIF[L,A] {
def empty : L
def head(l: L) : Option[A] 
def tail(l: L) : L 
def cons(a:A,l:L):L 
def append(l1: L, l2: L) : L
}

trait TreeIF[T,A] {
def empty : T 
def node(a:A,l:T,r:T):T 
def head(t: T) : Option[A] 
def left(t: T) : T
def right(t: T) : T
}
def testList[L](implicit LI: ListIF[L,Int], IT: Iter[L,Int]) { 
  val l = LI.cons(3, LI.cons(5, LI.cons(2, LI.cons(1, LI.empty)))) 
  println(sumElements(l)) //sumElements(l)(listIter[Int])
  printElements(l) //printElements(l)(listIter[Int])
}

def testTree[T](implicit TI: TreeIF[T,Int], ITR: Iterable[T,Int]) {
  val t: T = TI.node(3, TI.node(4, TI.empty, TI.empty), TI.node(2, TI.empty, TI.empty))
  println(sumElements2(t))
  printElements2(t)
}
sealed abstract class MyTree[A]
case class Empty[A]() extends MyTree[A]
case class Node[A](value: A, left: MyTree[A], right: MyTree[A]) extends MyTree[A]

implicit def treeIF[A] : TreeIF[MyTree[A],A] = new TreeIF[MyTree[A],A] {
  def empty = Empty()
  def node(a: A, l: MyTree[A], r: MyTree[A]) = Node(a,l,r) 
  def head(t: MyTree[A]) = t match {
    case Empty() => None
	case Node(v,_,_) => Some(v) 
    } 
  def left(t: MyTree[A]) = t match {
	case Empty() => t
	case Node(_,lt,_) => lt 
    }
  def right(t: MyTree[A]) = t match {
	case Empty() => t
	case Node(_,_,rt) => rt } 
}

 

 

 

 

슬라이드 233쪽

def treeIterable[L,A](implicit IF: ListIF[L,A], IT: Iter[L,A]) : Iterable[MyTree[A], Anew Iterable[MyTree[A], A] {

  type Itr=L
  def iter(a: MyTree[A]): L = a match {

     case Empty() => IF.empty

     case Node(v, left, right) => IF.cons (v, IF.append(iter(left), iter(right)))

   } 

  val iterIF = IT

}

 

implicit def treeIterableList[A] = treeIterable[List[A],A]

 

 

이와 같이 코드를 interface level에서 작성해두면 list --> lazylist로 변환하기가 수월해 지는 등의 장점이 생김. 

 

 

 

지난주 화, 목 수업 내용 매우 중요함.

지금까지의 내용이 중요하고 이 뒤는 중요도가 조금 떨어짐.

 

** 뭐랑 뭐가 연관이 됐는지가 명확하고 dependency가 뚜렷한 것. --> 교수님이 추구하셨던 코딩

내 코드가 수정이 됐을 때 어떤 영향을 미치는지도 명확하고 .. 

 

 

 

슬라이드 235쪽

Refined Interfaces

trait ListProdIF[L,A] {
  def empty : L 
  def cons(a:A,l:L):L 
  def append(l1: L, l2: L) : L
}

def treeIterable[L,A](implicit IF: ListProdIF[L,A], IT: Iter[L,A]) = 
  new Iterable[MyTree[A], A] {
	type Itr=L
	def iter(a: MyTree[A]): L = a match {
	  case Empty() => IF.empty 
          case Node(v, left, right) => IF.cons (v, IF.append(iter(left), iter(right))) 
    } 
      val iterIF = IT 
 }
 
 implicit def treeIterableList[A] = treeIterable[List[A],A]

 

 

Linking Modules

implicit def List2ListProdIF[L,A](implicit IF: ListIF[L,A]) : ListProdIF[L,A] =
  new ListProdIF[L,A] {
	def empty = IF.empty
	def cons(a: A, l: L) = IF.cons(a,l)
	def append(l1: L, l2: L) = IF.append(l1, l2)
  }
  
testList[List[Int]]
testTree[MyTree[Int]]

interface를 다양하게 입맛대로 만들 수 있음.

 

 

Iter being Iterable

implicit def iterIterable[I,A](implicit IT: Iter[I,A]) : Iterable[I,A] =
  new Iterable[I, A] { 
	type Itr = I
	val iterIF = IT 
	def iter(a: I) = a
}
val l = List(3,5,2,1)
sumElements2(l) //sumElements2(iterIterable(listIter[Int])) 
printElements2(l) //printElements2(iterIterable(listIter[Int]))

I에 대한 Iter --> I에 대한 Iterable도 무조건 만들 수 있음.

 

 

 

Type class는 어떤 타입인지에 대해 상관없음. OOP 스타일이 들어와도 ㄱㅊ음.

OOP에서는 상속(extends ~~~ )을 받았어야 됐지만 타입클래스에서는 상속을 받지 않아도 됨. 

 

 

 

 

 

Higer-kind Type Classes

https://twitter.github.io/scala_school/ko/index.html