Collection-Library


In [0]:
// 강사님이 만들어두신 MAYBE, LINKEDLIST

In [3]:
sealed trait Maybe[+A]
case object Empty extends Maybe[Nothing]
case class Just[A](a: A) extends Maybe[A]

sealed trait LinkedList[+A]
case object End extends LinkedList[Nothing]
final case class Pair[A](head: A, tail: LinkedList[A]) extends LinkedList[A]
object LinkedList {
  def apply[A](xs: A*): LinkedList[A] =
    if (xs.isEmpty) End else Pair(xs.head, apply(xs.tail: _*))
}


Out[3]:
defined trait Maybe
defined object Empty
defined class Just
defined trait LinkedList
defined object End
defined class Pair
defined object LinkedList

In [4]:
val l = LinkedList(1, 2, 3,4, 5)
println(l)


Pair(1,Pair(2,Pair(3,Pair(4,Pair(5,End)))))
Out[4]:
l: LinkedList[Int] = Pair(1,Pair(2,Pair(3,Pair(4,Pair(5,End)))))

In [4]:
// GET 함수 구현
def get(n: Int): Maybe[A] = ???


cmd4.sc:1: not found: type A
def get(n: Int): Maybe[A] = ???
                       ^
Compilation Failed

In [8]:
sealed trait Maybe[+A]
case object Empty extends Maybe[Nothing]
case class Just[A](a: A) extends Maybe[A]

sealed trait LinkedList[+A] {
    def get(n: Int): Maybe[A] = this match {
        case End => Empty
        case Pair(h, t) => if (n == 0) Just(h) else t.get(n-1)
    }
}
case object End extends LinkedList[Nothing]
final case class Pair[A](head: A, tail: LinkedList[A]) extends LinkedList[A]
object LinkedList {
  def apply[A](xs: A*): LinkedList[A] =
    if (xs.isEmpty) End else Pair(xs.head, apply(xs.tail: _*))
}


Out[8]:
defined trait Maybe
defined object Empty
defined class Just
defined trait LinkedList
defined object End
defined class Pair
defined object LinkedList

In [9]:
val l = LinkedList(1, 2, 3, 4, 5)
assert(l.get(0) == Just(1))
assert(l.get(6) == Empty)
println("ok!")


ok!
Out[9]:
l: LinkedList[Int] = Pair(1,Pair(2,Pair(3,Pair(4,Pair(5,End)))))

Length


In [22]:
sealed trait Maybe[+A]
case object Empty extends Maybe[Nothing]
case class Just[A](a: A) extends Maybe[A]

sealed trait LinkedList[+A] {
    def get(n: Int): Maybe[A] = this match {
        case End => Empty
        case Pair(h, t) => if (n == 0) Just(h) else t.get(n-1)
    }
    def length: Int = this match {
        case End => 0
        case Pair(h, t) => 1 + t.length
    }
}
case object End extends LinkedList[Nothing]
final case class Pair[A](head: A, tail: LinkedList[A]) extends LinkedList[A]
object LinkedList {
  def apply[A](xs: A*): LinkedList[A] =
    if (xs.isEmpty) End else Pair(xs.head, apply(xs.tail: _*))
}


Out[22]:
defined trait Maybe
defined object Empty
defined class Just
defined trait LinkedList
defined object End
defined class Pair
defined object LinkedList

In [23]:
val l = LinkedList(1, 2, 3, 4, 5)
assert(l.get(0) == Just(1))
assert(l.get(6) == Empty)
assert(End.length == 0)
assert(l.length == 5)
println("ok!")


ok!
Out[23]:
l: LinkedList[Int] = Pair(1,Pair(2,Pair(3,Pair(4,Pair(5,End)))))

In [24]:
// get은 Tail recursion을 사용 가능 ( 호출하고 그 다음에 사용하는 것이 없음 )
// length는 그냥은 안됨 (1을 더하니깐)
sealed trait Maybe[+A]
case object Empty extends Maybe[Nothing]
case class Just[A](a: A) extends Maybe[A]

sealed trait LinkedList[+A] {
    @annotation.tailrec
    def get(n: Int): Maybe[A] = this match {
        case End => Empty
        case Pair(h, t) => if (n == 0) Just(h) else t.get(n-1)
    }
    def length: Int = this match {
        case End => 0
        case Pair(h, t) => 1 + t.length
    }
}
case object End extends LinkedList[Nothing]
final case class Pair[A](head: A, tail: LinkedList[A]) extends LinkedList[A]
object LinkedList {
  def apply[A](xs: A*): LinkedList[A] =
    if (xs.isEmpty) End else Pair(xs.head, apply(xs.tail: _*))
}


Out[24]:
defined trait Maybe
defined object Empty
defined class Just
defined trait LinkedList
defined object End
defined class Pair
defined object LinkedList

In [ ]:
// length을 Tail recursion하려면 아래와 같이
sealed trait Maybe[+A]
case object Empty extends Maybe[Nothing]
case class Just[A](a: A) extends Maybe[A]

sealed trait LinkedList[+A] {
  @annotation.tailrec
  def get(n: Int): Maybe[A] = this match {
    case End => Empty
    case Pair(h, t) => if (n == 0) Just(h) else t.get(n - 1)
  }

  def length: Int = length()

  @annotation.tailrec
  def length(acc: Int = 0): Int = this match {
    case End => acc
    case Pair(h, t) => t.length(acc + 1)
  }
}
case object End extends LinkedList[Nothing]
final case class Pair[A](head: A, tail: LinkedList[A]) extends LinkedList[A]
object LinkedList {
 def apply[A](xs: A*): LinkedList[A] =
   if (xs.isEmpty) End else Pair(xs.head, apply(xs.tail: _*))
}

In [24]:
val l = LinkedList(1, 2, 3, 4, 5)
assert(l.get(0) == Just(1))
assert(l.get(6) == Empty)
assert(End.length == 0)
assert(l.length == 5)
println("Ok!")

contains


In [24]:
def contains[AA >: A](elem: AA): Boolean = ???

In [25]:
sealed trait Maybe[+A]
case object Empty extends Maybe[Nothing]
case class Just[A](a: A) extends Maybe[A]

sealed trait LinkedList[+A] {
  @annotation.tailrec
  def get(n: Int): Maybe[A] = this match {
    case End => Empty
    case Pair(h, t) => if (n == 0) Just(h) else t.get(n - 1)
  }

  def length: Int = length()

  @annotation.tailrec
  def length(acc: Int = 0): Int = this match {
    case End => acc
    case Pair(h, t) => t.length(acc + 1)
  }

  @annotation.tailrec
  def contains[AA >: A](elem: AA): Boolean = this match {
    case End => false
    case Pair(h, t) => if (h == elem) true else t.contains(elem)
  }
}
case object End extends LinkedList[Nothing]
final case class Pair[A](head: A, tail: LinkedList[A]) extends LinkedList[A]
object LinkedList {
 def apply[A](xs: A*): LinkedList[A] =
   if (xs.isEmpty) End else Pair(xs.head, apply(xs.tail: _*))
}


Out[25]:
defined trait Maybe
defined object Empty
defined class Just
defined trait LinkedList
defined object End
defined class Pair
defined object LinkedList

In [47]:
sealed trait Maybe[+A]
case object Empty extends Maybe[Nothing]
case class Just[A](a: A) extends Maybe[A]

sealed trait LinkedList[+A] {
  @annotation.tailrec
  def get(n: Int): Maybe[A] = this match {
    case End => Empty
    case Pair(h, t) => if (n == 0) Just(h) else t.get(n - 1)
  }

  def length: Int = length()

  @annotation.tailrec
  def length(acc: Int = 0): Int = this match {
    case End => acc
    case Pair(h, t) => t.length(acc + 1)
  }

  @annotation.tailrec
  def contains[AA >: A](elem: AA): Boolean = this match {
    case End => false
    case Pair(h, t) => if (h == elem) true else t.contains(elem)
  }

}
case object End extends LinkedList[Nothing]
final case class Pair[A](head: A, tail: LinkedList[A]) extends LinkedList[A]
object LinkedList {
 def apply[A](xs: A*): LinkedList[A] =
   if (xs.isEmpty) End else Pair(xs.head, apply(xs.tail: _*))
}


Out[47]:
defined trait Maybe
defined object Empty
defined class Just
defined trait LinkedList
defined object End
defined class Pair
defined object LinkedList

In [48]:
val l = LinkedList(1, 2, 3, 4, 5)
assert(l.get(0) == Just(1))
assert(l.get(6) == Empty)
assert(End.length == 0)
assert(l.length == 5)
assert(l.contains(1) == true)
assert(l.contains(0) == false)

println("Ok!")


Ok!
Out[48]:
l: LinkedList[Int] = Pair(1,Pair(2,Pair(3,Pair(4,Pair(5,End)))))

Find

  • 특정 조건이 들어오고 이걸 True로 만들어주는 친구가 있는지 알려줌
  • 하나만 반환

In [ ]:
def find(p: A => Boolean): Maybe[A] = ???

In [44]:
sealed trait Maybe[+A]
case object Empty extends Maybe[Nothing]
case class Just[A](a: A) extends Maybe[A]

sealed trait LinkedList[+A] {
  @annotation.tailrec
  def get(n: Int): Maybe[A] = this match {
    case End => Empty
    case Pair(h, t) => if (n == 0) Just(h) else t.get(n - 1)
  }

  def length: Int = length()

  @annotation.tailrec
  def length(acc: Int = 0): Int = this match {
    case End => acc
    case Pair(h, t) => t.length(acc + 1)
  }

  @annotation.tailrec
  def contains[AA >: A](elem: AA): Boolean = this match {
    case End => false
    case Pair(h, t) => if (h == elem) true else t.contains(elem)
  }

  @annotation.tailrec
  def find(p: A => Boolean): Maybe[A] = this match {
    case End => Empty
    case Pair(h, t) => if (p(h)) Just(h) else t.find(p)
  }

}
case object End extends LinkedList[Nothing]
final case class Pair[A](head: A, tail: LinkedList[A]) extends LinkedList[A]
object LinkedList {
 def apply[A](xs: A*): LinkedList[A] =
   if (xs.isEmpty) End else Pair(xs.head, apply(xs.tail: _*))
}


Out[44]:
defined trait Maybe
defined object Empty
defined class Just
defined trait LinkedList
defined object End
defined class Pair
defined object LinkedList

In [45]:
val l = LinkedList(1, 2, 3, 4, 5)
assert(l.get(0) == Just(1))
assert(l.get(6) == Empty)
assert(End.length == 0)
assert(l.length == 5)
assert(l.contains(1) == true)
assert(l.contains(0) == false)
assert(l.find(_ % 2 == 0) == Just(2))
assert(l.find(_ % 6 == 0) == Empty)

println("Ok!")


Ok!
Out[45]:
l: LinkedList[Int] = Pair(1,Pair(2,Pair(3,Pair(4,Pair(5,End)))))

Filter


In [ ]:
def filter(p: A => Boolean): LinkedList[A] = ???

In [ ]:


In [42]:
sealed trait Maybe[+A]
case object Empty extends Maybe[Nothing]
case class Just[A](a: A) extends Maybe[A]

sealed trait LinkedList[+A] {
  @annotation.tailrec
  def get(n: Int): Maybe[A] = this match {
    case End => Empty
    case Pair(h, t) => if (n == 0) Just(h) else t.get(n - 1)
  }

  def length: Int = length()

  @annotation.tailrec
  def length(acc: Int = 0): Int = this match {
    case End => acc
    case Pair(h, t) => t.length(acc + 1)
  }

  @annotation.tailrec
  def contains[AA >: A](elem: AA): Boolean = this match {
    case End => false
    case Pair(h, t) => if (h == elem) true else t.contains(elem)
  }

  @annotation.tailrec
  def find(p: A => Boolean): Maybe[A] = this match {
    case End => Empty
    case Pair(h, t) => if (p(h)) Just(h) else t.find(p)
  }

  def filter(p: A => Boolean): LinkedList[A] = this match {
    case End => End
    case Pair(h, t) =>
      val tf = t filter p
      if (p(h)) Pair(h, tf) else tf
  }

}
case object End extends LinkedList[Nothing]
final case class Pair[A](head: A, tail: LinkedList[A]) extends LinkedList[A]
object LinkedList {
 def apply[A](xs: A*): LinkedList[A] =
   if (xs.isEmpty) End else Pair(xs.head, apply(xs.tail: _*))
}


Out[42]:
defined trait Maybe
defined object Empty
defined class Just
defined trait LinkedList
defined object End
defined class Pair
defined object LinkedList

In [43]:
val l = LinkedList(1, 2, 3, 4, 5)
assert(l.get(0) == Just(1))
assert(l.get(6) == Empty)
assert(End.length == 0)
assert(l.length == 5)
assert(l.contains(1) == true)
assert(l.contains(0) == false)
assert(l.find(_ % 2 == 0) == Just(2))
assert(l.find(_ % 6 == 0) == Empty)
assert(l.filter(_ % 2 == 0) == LinkedList(2, 4))
assert(l.filter(_ % 6 == 0) == LinkedList())

println("Ok!")


Ok!
Out[43]:
l: LinkedList[Int] = Pair(1,Pair(2,Pair(3,Pair(4,Pair(5,End)))))

MAP


In [ ]:
def map[B](f: A => B): LinkedList[B] = ???

In [ ]:
assert(l.map(_ + 1) == LinkedList(2, 3, 4, 5, 6))

In [37]:
sealed trait Maybe[+A]
case object Empty extends Maybe[Nothing]
case class Just[A](a: A) extends Maybe[A]

sealed trait LinkedList[+A] {
  @annotation.tailrec
  def get(n: Int): Maybe[A] = this match {
    case End => Empty
    case Pair(h, t) => if (n == 0) Just(h) else t.get(n - 1)
  }

  def length: Int = length()

  @annotation.tailrec
  def length(acc: Int = 0): Int = this match {
    case End => acc
    case Pair(h, t) => t.length(acc + 1)
  }

  @annotation.tailrec
  def contains[AA >: A](elem: AA): Boolean = this match {
    case End => false
    case Pair(h, t) => if (h == elem) true else t.contains(elem)
  }

  @annotation.tailrec
  def find(p: A => Boolean): Maybe[A] = this match {
    case End => Empty
    case Pair(h, t) => if (p(h)) Just(h) else t.find(p)
  }

  def filter(p: A => Boolean): LinkedList[A] = this match {
    case End => End
    case Pair(h, t) =>
      val tf = t filter p
      if (p(h)) Pair(h, tf) else tf
  }

  def map[B](f: A => B): LinkedList[B] = this match {
    case End => End
    case Pair(h, t) => Pair(f(h), t.map(f))
  }
  
}
case object End extends LinkedList[Nothing]
final case class Pair[A](head: A, tail: LinkedList[A]) extends LinkedList[A]
object LinkedList {
 def apply[A](xs: A*): LinkedList[A] =
   if (xs.isEmpty) End else Pair(xs.head, apply(xs.tail: _*))
}


Out[37]:
defined trait Maybe
defined object Empty
defined class Just
defined trait LinkedList
defined object End
defined class Pair
defined object LinkedList

In [38]:
val l = LinkedList(1, 2, 3, 4, 5)


Out[38]:
l: LinkedList[Int] = Pair(1,Pair(2,Pair(3,Pair(4,Pair(5,End)))))

In [41]:
assert(l.get(0) == Just(1))
assert(l.get(6) == Empty)
assert(End.length == 0)
assert(l.length == 5)
assert(l.contains(1) == true)
assert(l.contains(0) == false)
assert(l.find(_ % 2 == 0) == Just(2))
assert(l.find(_ % 6 == 0) == Empty)
assert(l.filter(_ % 2 == 0) == LinkedList(2, 4))
assert(l.filter(_ % 6 == 0) == LinkedList())
assert(l.map(_ + 1) == LinkedList(2, 3, 4, 5, 6))

println("Ok!")


Ok!

FLATMAP


In [ ]:
def flatMap[B](f: A => LinkedList[B]): LinkedList[B] = ???

In [ ]:
def ++ 해서.. (list 2 concat)

In [39]:
sealed trait Maybe[+A]
case object Empty extends Maybe[Nothing]
case class Just[A](a: A) extends Maybe[A]

sealed trait LinkedList[+A] {
  @annotation.tailrec
  def get(n: Int): Maybe[A] = this match {
    case End => Empty
    case Pair(h, t) => if (n == 0) Just(h) else t.get(n - 1)
  }

  def length: Int = length()

  @annotation.tailrec
  def length(acc: Int = 0): Int = this match {
    case End => acc
    case Pair(h, t) => t.length(acc + 1)
  }

  @annotation.tailrec
  def contains[AA >: A](elem: AA): Boolean = this match {
    case End => false
    case Pair(h, t) => if (h == elem) true else t.contains(elem)
  }

  @annotation.tailrec
  def find(p: A => Boolean): Maybe[A] = this match {
    case End => Empty
    case Pair(h, t) => if (p(h)) Just(h) else t.find(p)
  }

  def filter(p: A => Boolean): LinkedList[A] = this match {
    case End => End
    case Pair(h, t) =>
      val tf = t filter p
      if (p(h)) Pair(h, tf) else tf
  }

  def map[B](f: A => B): LinkedList[B] = this match {
    case End => End
    case Pair(h, t) => Pair(f(h), t.map(f))
  }
  
  def flatMap[B](f: A => LinkedList[B]): LinkedList[B] = this match {
    case End => End
    case Pair(h, t) => f(h) ++ t.flatMap(f)
  }

  def ++[AA >: A](that: LinkedList[AA]): LinkedList[AA] = this match {
    case End => that
    case Pair(h, t) => Pair(h, t ++ that)
  }

 
}
case object End extends LinkedList[Nothing]
final case class Pair[A](head: A, tail: LinkedList[A]) extends LinkedList[A]
object LinkedList {
 def apply[A](xs: A*): LinkedList[A] =
   if (xs.isEmpty) End else Pair(xs.head, apply(xs.tail: _*))
}


Out[39]:
defined trait Maybe
defined object Empty
defined class Just
defined trait LinkedList
defined object End
defined class Pair
defined object LinkedList

In [40]:
val l = LinkedList(1, 2, 3, 4, 5)
assert(l.get(0) == Just(1))
assert(l.get(6) == Empty)
assert(End.length == 0)
assert(l.length == 5)
assert(l.contains(1) == true)
assert(l.contains(0) == false)
assert(l.find(_ % 2 == 0) == Just(2))
assert(l.find(_ % 6 == 0) == Empty)
assert(l.filter(_ % 2 == 0) == LinkedList(2, 4))
assert(l.filter(_ % 6 == 0) == LinkedList())
assert(l.map(_ + 1) == LinkedList(2, 3, 4, 5, 6))
assert(l.flatMap(n => LinkedList(n, n + 1)) ==
  LinkedList(1, 2, 2, 3, 3, 4, 4, 5, 5, 6)
)
println("Ok!")


Ok!
Out[40]:
l: LinkedList[Int] = Pair(1,Pair(2,Pair(3,Pair(4,Pair(5,End)))))

In [ ]:

FOLDLEFT


In [49]:
sealed trait Maybe[+A]
case object Empty extends Maybe[Nothing]
case class Just[A](a: A) extends Maybe[A]

sealed trait LinkedList[+A] {
  @annotation.tailrec
  def get(n: Int): Maybe[A] = this match {
    case End => Empty
    case Pair(h, t) => if (n == 0) Just(h) else t.get(n - 1)
  }

  def length: Int = length()

  @annotation.tailrec
  def length(acc: Int = 0): Int = this match {
    case End => acc
    case Pair(h, t) => t.length(acc + 1)
  }

  @annotation.tailrec
  def contains[AA >: A](elem: AA): Boolean = this match {
    case End => false
    case Pair(h, t) => if (h == elem) true else t.contains(elem)
  }

  @annotation.tailrec
  def find(p: A => Boolean): Maybe[A] = this match {
    case End => Empty
    case Pair(h, t) => if (p(h)) Just(h) else t.find(p)
  }

  def filter(p: A => Boolean): LinkedList[A] = this match {
    case End => End
    case Pair(h, t) =>
      val tf = t filter p
      if (p(h)) Pair(h, tf) else tf
  }

  def map[B](f: A => B): LinkedList[B] = this match {
    case End => End
    case Pair(h, t) => Pair(f(h), t.map(f))
  }
  
  def flatMap[B](f: A => LinkedList[B]): LinkedList[B] = this match {
    case End => End
    case Pair(h, t) => f(h) ++ t.flatMap(f)
  }

  def ++[AA >: A](that: LinkedList[AA]): LinkedList[AA] = this match {
    case End => that
    case Pair(h, t) => Pair(h, t ++ that)
  }

  def foldLeft[B](z: B)(op: (B, A) => B): B = this match {
      case End => z
      case Pair(h, t) => t.foldLeft(op(z, h))(op)
  }
}
case object End extends LinkedList[Nothing]
final case class Pair[A](head: A, tail: LinkedList[A]) extends LinkedList[A]
object LinkedList {
 def apply[A](xs: A*): LinkedList[A] =
   if (xs.isEmpty) End else Pair(xs.head, apply(xs.tail: _*))
}


Out[49]:
defined trait Maybe
defined object Empty
defined class Just
defined trait LinkedList
defined object End
defined class Pair
defined object LinkedList

In [50]:
val l = LinkedList(1, 2, 3, 4, 5)
assert(l.foldLeft("")(_ + _ + 1) == "1121314151")
assert(l.get(0) == Just(1))
assert(l.get(6) == Empty)
assert(End.length == 0)
assert(l.length == 5)
assert(l.contains(1) == true)
assert(l.contains(0) == false)
assert(l.find(_ % 2 == 0) == Just(2))
assert(l.find(_ % 6 == 0) == Empty)
assert(l.filter(_ % 2 == 0) == LinkedList(2, 4))
assert(l.filter(_ % 6 == 0) == LinkedList())
assert(l.map(_ + 1) == LinkedList(2, 3, 4, 5, 6))
assert(l.flatMap(n => LinkedList(n, n + 1)) ==
  LinkedList(1, 2, 2, 3, 3, 4, 4, 5, 5, 6)
)
println("Ok!")


Ok!
Out[50]:
l: LinkedList[Int] = Pair(1,Pair(2,Pair(3,Pair(4,Pair(5,End)))))

FoldRight(1/2)


In [ ]:
def foldRight[B](z: B)(op: (A, B) => B): B = ???

In [52]:
sealed trait Maybe[+A]
case object Empty extends Maybe[Nothing]
case class Just[A](a: A) extends Maybe[A]

sealed trait LinkedList[+A] {
  @annotation.tailrec
  def get(n: Int): Maybe[A] = this match {
    case End => Empty
    case Pair(h, t) => if (n == 0) Just(h) else t.get(n - 1)
  }

  def length: Int = length()

  @annotation.tailrec
  def length(acc: Int = 0): Int = this match {
    case End => acc
    case Pair(h, t) => t.length(acc + 1)
  }

  @annotation.tailrec
  def contains[AA >: A](elem: AA): Boolean = this match {
    case End => false
    case Pair(h, t) => if (h == elem) true else t.contains(elem)
  }

  @annotation.tailrec
  def find(p: A => Boolean): Maybe[A] = this match {
    case End => Empty
    case Pair(h, t) => if (p(h)) Just(h) else t.find(p)
  }

  def filter(p: A => Boolean): LinkedList[A] = this match {
    case End => End
    case Pair(h, t) =>
      val tf = t filter p
      if (p(h)) Pair(h, tf) else tf
  }

  def map[B](f: A => B): LinkedList[B] = this match {
    case End => End
    case Pair(h, t) => Pair(f(h), t.map(f))
  }
  
  def flatMap[B](f: A => LinkedList[B]): LinkedList[B] = this match {
    case End => End
    case Pair(h, t) => f(h) ++ t.flatMap(f)
  }

  def ++[AA >: A](that: LinkedList[AA]): LinkedList[AA] = this match {
    case End => that
    case Pair(h, t) => Pair(h, t ++ that)
  }

  def foldLeft[B](z: B)(op: (B, A) => B): B = this match {
      case End => z
      case Pair(h, t) => t.foldLeft(op(z, h))(op)
  }
    
  def foldRight[B](z: B)(op: (A, B) => B): B = this match {
      case End => z
      case Pair(h, t) => op(h, t.foldRight(z)(op))
  }
}
case object End extends LinkedList[Nothing]
final case class Pair[A](head: A, tail: LinkedList[A]) extends LinkedList[A]
object LinkedList {
 def apply[A](xs: A*): LinkedList[A] =
   if (xs.isEmpty) End else Pair(xs.head, apply(xs.tail: _*))
}


Out[52]:
defined trait Maybe
defined object Empty
defined class Just
defined trait LinkedList
defined object End
defined class Pair
defined object LinkedList

In [54]:
val l = LinkedList(1, 2, 3, 4, 5)
assert(l.foldRight("")(1 + _ + _) == "23456")
assert(l.foldLeft("")(_ + _ + 1) == "1121314151")
assert(l.get(0) == Just(1))
assert(l.get(6) == Empty)
assert(End.length == 0)
assert(l.length == 5)
assert(l.contains(1) == true)
assert(l.contains(0) == false)
assert(l.find(_ % 2 == 0) == Just(2))
assert(l.find(_ % 6 == 0) == Empty)
assert(l.filter(_ % 2 == 0) == LinkedList(2, 4))
assert(l.filter(_ % 6 == 0) == LinkedList())
assert(l.map(_ + 1) == LinkedList(2, 3, 4, 5, 6))
assert(l.flatMap(n => LinkedList(n, n + 1)) ==
  LinkedList(1, 2, 2, 3, 3, 4, 4, 5, 5, 6)
)
println("Ok!")


Ok!
Out[54]:
l: LinkedList[Int] = Pair(1,Pair(2,Pair(3,Pair(4,Pair(5,End)))))

Reverse

  • hint : foldLeft 이용

In [ ]:
def reverse: LinkedList[A] = ???

In [55]:
sealed trait Maybe[+A]
case object Empty extends Maybe[Nothing]
case class Just[A](a: A) extends Maybe[A]

sealed trait LinkedList[+A] {
  @annotation.tailrec
  def get(n: Int): Maybe[A] = this match {
    case End => Empty
    case Pair(h, t) => if (n == 0) Just(h) else t.get(n - 1)
  }

  def length: Int = length()

  @annotation.tailrec
  def length(acc: Int = 0): Int = this match {
    case End => acc
    case Pair(h, t) => t.length(acc + 1)
  }

  @annotation.tailrec
  def contains[AA >: A](elem: AA): Boolean = this match {
    case End => false
    case Pair(h, t) => if (h == elem) true else t.contains(elem)
  }

  @annotation.tailrec
  def find(p: A => Boolean): Maybe[A] = this match {
    case End => Empty
    case Pair(h, t) => if (p(h)) Just(h) else t.find(p)
  }

  def filter(p: A => Boolean): LinkedList[A] = this match {
    case End => End
    case Pair(h, t) =>
      val tf = t filter p
      if (p(h)) Pair(h, tf) else tf
  }

  def map[B](f: A => B): LinkedList[B] = this match {
    case End => End
    case Pair(h, t) => Pair(f(h), t.map(f))
  }
  
  def flatMap[B](f: A => LinkedList[B]): LinkedList[B] = this match {
    case End => End
    case Pair(h, t) => f(h) ++ t.flatMap(f)
  }

  def ++[AA >: A](that: LinkedList[AA]): LinkedList[AA] = this match {
    case End => that
    case Pair(h, t) => Pair(h, t ++ that)
  }

  def foldLeft[B](z: B)(op: (B, A) => B): B = this match {
      case End => z
      case Pair(h, t) => t.foldLeft(op(z, h))(op)
  }
    
  def foldRight[B](z: B)(op: (A, B) => B): B = this match {
      case End => z
      case Pair(h, t) => op(h, t.foldRight(z)(op))
  }

  def reverse: LinkedList[A] = foldLeft[LinkedList[A]](End){ // LinkedList[A] Type이라고 명시
      (list, a) => Pair(a, list)
  }
    
}
case object End extends LinkedList[Nothing]
final case class Pair[A](head: A, tail: LinkedList[A]) extends LinkedList[A]
object LinkedList {
 def apply[A](xs: A*): LinkedList[A] =
   if (xs.isEmpty) End else Pair(xs.head, apply(xs.tail: _*))
}


Out[55]:
defined trait Maybe
defined object Empty
defined class Just
defined trait LinkedList
defined object End
defined class Pair
defined object LinkedList

In [56]:
val l = LinkedList(1, 2, 3, 4, 5)
assert(l.reverse == LinkedList(5, 4, 3, 2, 1))
assert(l.foldRight("")(1 + _ + _) == "23456")
assert(l.foldLeft("")(_ + _ + 1) == "1121314151")
assert(l.get(0) == Just(1))
assert(l.get(6) == Empty)
assert(End.length == 0)
assert(l.length == 5)
assert(l.contains(1) == true)
assert(l.contains(0) == false)
assert(l.find(_ % 2 == 0) == Just(2))
assert(l.find(_ % 6 == 0) == Empty)
assert(l.filter(_ % 2 == 0) == LinkedList(2, 4))
assert(l.filter(_ % 6 == 0) == LinkedList())
assert(l.map(_ + 1) == LinkedList(2, 3, 4, 5, 6))
assert(l.flatMap(n => LinkedList(n, n + 1)) ==
  LinkedList(1, 2, 2, 3, 3, 4, 4, 5, 5, 6)
)
println("Ok!")


Ok!
Out[56]:
l: LinkedList[Int] = Pair(1,Pair(2,Pair(3,Pair(4,Pair(5,End)))))

FOLDRIGHT(2/2)

  • foldLeft는 쉽게 tail recursion을 적용해 구현할 수 있는 반면, foldRight를 그냥 구현하면 tail recursion이 적용되지 않는 형태가 되기 쉽습니다.

  • foldRight을 foldLeft를 써서 구현해보세요.


In [57]:
sealed trait Maybe[+A]
case object Empty extends Maybe[Nothing]
case class Just[A](a: A) extends Maybe[A]

sealed trait LinkedList[+A] {
  @annotation.tailrec
  def get(n: Int): Maybe[A] = this match {
    case End => Empty
    case Pair(h, t) => if (n == 0) Just(h) else t.get(n - 1)
  }

  def length: Int = length()

  @annotation.tailrec
  def length(acc: Int = 0): Int = this match {
    case End => acc
    case Pair(h, t) => t.length(acc + 1)
  }

  @annotation.tailrec
  def contains[AA >: A](elem: AA): Boolean = this match {
    case End => false
    case Pair(h, t) => if (h == elem) true else t.contains(elem)
  }

  @annotation.tailrec
  def find(p: A => Boolean): Maybe[A] = this match {
    case End => Empty
    case Pair(h, t) => if (p(h)) Just(h) else t.find(p)
  }

  def filter(p: A => Boolean): LinkedList[A] = this match {
    case End => End
    case Pair(h, t) =>
      val tf = t filter p
      if (p(h)) Pair(h, tf) else tf
  }

  def map[B](f: A => B): LinkedList[B] = this match {
    case End => End
    case Pair(h, t) => Pair(f(h), t.map(f))
  }
  
  def flatMap[B](f: A => LinkedList[B]): LinkedList[B] = this match {
    case End => End
    case Pair(h, t) => f(h) ++ t.flatMap(f)
  }

  def ++[AA >: A](that: LinkedList[AA]): LinkedList[AA] = this match {
    case End => that
    case Pair(h, t) => Pair(h, t ++ that)
  }
    
  @annotation.tailrec
  def foldLeft[B](z: B)(op: (B, A) => B): B = this match {
      case End => z
      case Pair(h, t) => t.foldLeft(op(z, h))(op)
  }
    
  def foldRight[B](z: B)(op: (A, B) => B): B = reverse.foldLeft(z){
      (b, a) => op(a, b)
  }
    
  def reverse: LinkedList[A] = foldLeft[LinkedList[A]](End){ 
      (list, a) => Pair(a, list)
  }
    
}
case object End extends LinkedList[Nothing]
final case class Pair[A](head: A, tail: LinkedList[A]) extends LinkedList[A]
object LinkedList {
 def apply[A](xs: A*): LinkedList[A] =
   if (xs.isEmpty) End else Pair(xs.head, apply(xs.tail: _*))
}


Out[57]:
defined trait Maybe
defined object Empty
defined class Just
defined trait LinkedList
defined object End
defined class Pair
defined object LinkedList

In [58]:
val l = LinkedList(1, 2, 3, 4, 5)
assert(l.reverse == LinkedList(5, 4, 3, 2, 1))
assert(l.foldRight("")(1 + _ + _) == "23456")
assert(l.foldLeft("")(_ + _ + 1) == "1121314151")
assert(l.get(0) == Just(1))
assert(l.get(6) == Empty)
assert(End.length == 0)
assert(l.length == 5)
assert(l.contains(1) == true)
assert(l.contains(0) == false)
assert(l.find(_ % 2 == 0) == Just(2))
assert(l.find(_ % 6 == 0) == Empty)
assert(l.filter(_ % 2 == 0) == LinkedList(2, 4))
assert(l.filter(_ % 6 == 0) == LinkedList())
assert(l.map(_ + 1) == LinkedList(2, 3, 4, 5, 6))
assert(l.flatMap(n => LinkedList(n, n + 1)) ==
  LinkedList(1, 2, 2, 3, 3, 4, 4, 5, 5, 6)
)
println("Ok!")


Ok!
Out[58]:
l: LinkedList[Int] = Pair(1,Pair(2,Pair(3,Pair(4,Pair(5,End)))))

실습 Part 2


In [59]:
def sum(f: Int => Int)(a: Int, b: Int) = (a to b map f).sum


Out[59]:
defined function sum

In [61]:
sum(x => x * x)(1, 10)
// 1부터 10까지의 합


Out[61]:
res60: Int = 385

In [62]:
sum(_ * 2)(1, 10)


Out[62]:
res61: Int = 110

In [63]:
def f(a: Int, b: Int): Int = a * b


Out[63]:
defined function f

In [64]:
def g(a: Int)(b: Int): Int = a * b


Out[64]:
defined function g

In [65]:
f(2, 3)


Out[65]:
res64: Int = 6

In [66]:
g(2)(3)


Out[66]:
res65: Int = 6

In [67]:
sum(g(2))(1,10)


Out[67]:
res66: Int = 110

In [68]:
val pair = ("ans", 42)


Out[68]:
pair: (String, Int) = ("ans", 42)

In [71]:
val (label, value) = pair


Out[71]:
label: String = "ans"
value: Int = 42

In [70]:
pair._1


Out[70]:
res69: String = "ans"

In [72]:
pair._2


Out[72]:
res71: Int = 42

In [72]:
pair._0


cmd72.sc:1: value _0 is not a member of (String, Int)
val res72 = pair._0
                 ^
Compilation Failed

In [73]:
val List(a, b, c) = List(1, 2, 3)


Out[73]:
a: Int = 1
b: Int = 2
c: Int = 3

In [74]:
val Array(a, b, c) = "1 2 3" split ' '


Out[74]:
a: String = "1"
b: String = "2"
c: String = "3"

In [75]:
1 to 10


Out[75]:
res74: Range.Inclusive = Range(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

In [76]:
1 until 10


Out[76]:
res75: Range = Range(1, 2, 3, 4, 5, 6, 7, 8, 9)

In [77]:
1 to 10 by 3


Out[77]:
res76: Range = Range(1, 4, 7, 10)

In [78]:
6 to 1 by -2


Out[78]:
res77: Range = Range(6, 4, 2)

In [79]:
1.to(10)


Out[79]:
res78: Range.Inclusive = Range(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

In [81]:
val aaa = Seq(1, 1, 2, 2, 3, 3)


Out[81]:
aaa: Seq[Int] = List(1, 1, 2, 2, 3, 3)

In [83]:
Set(1, 1, 2, 2, 3, 3)


Out[83]:
res82: Set[Int] = Set(1, 2, 3)

In [84]:
IndexedSeq(1, 2, 3)


Out[84]:
res83: IndexedSeq[Int] = Vector(1, 2, 3)

In [85]:
IndexedSeq(1, 2, 3) :+ 4


Out[85]:
res84: IndexedSeq[Int] = Vector(1, 2, 3, 4)

In [86]:
0 +: IndexedSeq(1, 2, 3)


Out[86]:
res85: IndexedSeq[Int] = Vector(0, 1, 2, 3)

In [87]:
List(1, 2, 3)


Out[87]:
res86: List[Int] = List(1, 2, 3)

In [88]:
1::(2::(3::Nil))


Out[88]:
res87: List[Int] = List(1, 2, 3)

In [89]:
1::2::3::Nil


Out[89]:
res88: List[Int] = List(1, 2, 3)

In [90]:
Nil.::(3).::(2).::(1)


Out[90]:
res89: List[Int] = List(1, 2, 3)

In [91]:
val (xs, ys) = (List(1, 1, 2, 2, 3, 3), IndexedSeq(1, 2, 3))


Out[91]:
xs: List[Int] = List(1, 1, 2, 2, 3, 3)
ys: IndexedSeq[Int] = Vector(1, 2, 3)

In [92]:
xs.head


Out[92]:
res91: Int = 1

In [93]:
xs.tail


Out[93]:
res92: List[Int] = List(1, 2, 2, 3, 3)

In [94]:
ys.last


Out[94]:
res93: Int = 3

In [95]:
ys.init


Out[95]:
res94: IndexedSeq[Int] = Vector(1, 2)

In [96]:
ys.head


Out[96]:
res95: Int = 1

In [97]:
xs take 4


Out[97]:
res96: List[Int] = List(1, 1, 2, 2)

In [98]:
xs drop 4


Out[98]:
res97: List[Int] = List(3, 3)

In [99]:
ys(1)


Out[99]:
res98: Int = 2

In [100]:
xs ++ ys


Out[100]:
res99: List[Int] = List(1, 1, 2, 2, 3, 3, 1, 2, 3)

In [101]:
xs


Out[101]:
res100: List[Int] = List(1, 1, 2, 2, 3, 3)

In [102]:
ys


Out[102]:
res101: IndexedSeq[Int] = Vector(1, 2, 3)

In [103]:
ys ++ xs


Out[103]:
res102: IndexedSeq[Int] = Vector(1, 2, 3, 1, 1, 2, 2, 3, 3)

In [103]:
// 앞의 자료형을 따라감

In [104]:
xs.reverse


Out[104]:
res103: List[Int] = List(3, 3, 2, 2, 1, 1)

In [105]:
ys updated(1, 10)


Out[105]:
res104: IndexedSeq[Int] = Vector(1, 10, 3)

In [106]:
ys


Out[106]:
res105: IndexedSeq[Int] = Vector(1, 2, 3)

In [107]:
xs indexOf 3


Out[107]:
res106: Int = 4

In [108]:
xs contains 3


Out[108]:
res107: Boolean = true

In [109]:
xs contains 4


Out[109]:
res108: Boolean = false

In [110]:
xs zip ys


Out[110]:
res109: List[(Int, Int)] = List((1, 1), (1, 2), (2, 3))

In [111]:
ys zip xs


Out[111]:
res110: IndexedSeq[(Int, Int)] = Vector((1, 1), (2, 1), (3, 2))

In [112]:
xs.sum


Out[112]:
res111: Int = 12

In [113]:
xs.product


Out[113]:
res112: Int = 36

In [114]:
xs


Out[114]:
res113: List[Int] = List(1, 1, 2, 2, 3, 3)

In [115]:
xs.max


Out[115]:
res114: Int = 3

In [116]:
xs.min


Out[116]:
res115: Int = 1

In [117]:
xs filter (x => x%2 == 0)


Out[117]:
res116: List[Int] = List(2, 2)

In [118]:
xs filterNot (x => x%2 ==0)


Out[118]:
res117: List[Int] = List(1, 1, 3, 3)

In [119]:
xs filter (_%2 == 0)


Out[119]:
res118: List[Int] = List(2, 2)

In [120]:
xs partition (_%2 == 0)


Out[120]:
res119: (List[Int], List[Int]) = (List(2, 2), List(1, 1, 3, 3))

In [121]:
xs takeWhile (_%3 > 0)


Out[121]:
res120: List[Int] = List(1, 1, 2, 2)

In [122]:
xs


Out[122]:
res121: List[Int] = List(1, 1, 2, 2, 3, 3)

In [123]:
xs dropWhile (_%3 > 0)


Out[123]:
res122: List[Int] = List(3, 3)

In [124]:
xs span (_%3 > 0)


Out[124]:
res123: (List[Int], List[Int]) = (List(1, 1, 2, 2), List(3, 3))

In [125]:
xs map (x => x * 2)


Out[125]:
res124: List[Int] = List(2, 2, 4, 4, 6, 6)

In [131]:
xs map square


cmd131.sc:1: not found: value square
val res131 = xs map square
                    ^
Compilation Failed

In [126]:
xs groupBy (_ % 2)


Out[126]:
res125: Map[Int, List[Int]] = Map(1 -> List(1, 1, 3, 3), 0 -> List(2, 2))

In [128]:
xs.reduceLeft((acc, x) => acc + x)


Out[128]:
res127: Int = 12

In [129]:
xs.foldLeft(10)((acc, x) => acc + x)


Out[129]:
res128: Int = 22

In [130]:
xs.foldLeft(10)(_ + _)


Out[130]:
res129: Int = 22

In [131]:
(10 /: xs)(_ + _)


Out[131]:
res130: Int = 22

SEQ

    • 숫자열
    • 문자열
  • apply method를 사용해서 만들면 default로 list로 만들어짐

In [132]:
val sequence = Seq(1, 2, 3)


Out[132]:
sequence: Seq[Int] = List(1, 2, 3)

In [133]:
sequence.apply(0)


Out[133]:
res132: Int = 1

In [134]:
sequence(0)


Out[134]:
res133: Int = 1

In [135]:
sequence(3)


java.lang.IndexOutOfBoundsException: 3
  scala.collection.LinearSeqOptimized$class.apply(LinearSeqOptimized.scala:65)
  scala.collection.immutable.List.apply(List.scala:84)
  $sess.cmd134Wrapper$Helper.<init>(cmd134.sc:1)
  $sess.cmd134Wrapper.<init>(cmd134.sc:1149)
  $sess.cmd134$.<init>(cmd134.sc:597)
  $sess.cmd134$.<clinit>(cmd134.sc:-1)

In [137]:
sequence(-1)
// - dksehlsp


java.lang.IndexOutOfBoundsException: -1
  scala.collection.LinearSeqOptimized$class.apply(LinearSeqOptimized.scala:65)
  scala.collection.immutable.List.apply(List.scala:84)
  $sess.cmd136Wrapper$Helper.<init>(cmd136.sc:1)
  $sess.cmd136Wrapper.<init>(cmd136.sc:1149)
  $sess.cmd136$.<init>(cmd136.sc:597)
  $sess.cmd136$.<clinit>(cmd136.sc:-1)

In [138]:
sequence.head


Out[138]:
res137: Int = 1

In [139]:
sequence.tail


Out[139]:
res138: Seq[Int] = List(2, 3)

In [141]:
sequence.headOption
// exception을 안 일으키고 작성 가능


Out[141]:
res140: Option[Int] = Some(1)

In [142]:
sequence.length


Out[142]:
res141: Int = 3

In [143]:
sequence.contains(2)


Out[143]:
res142: Boolean = true

In [144]:
sequence.find(_ == 3)


Out[144]:
res143: Option[Int] = Some(3)

In [145]:
sequence.find(_ > 4)


Out[145]:
res144: Option[Int] = None

In [146]:
sequence.filter(_ > 1)


Out[146]:
res145: Seq[Int] = List(2, 3)

In [147]:
sequence.sortWith(_ >  _)


Out[147]:
res146: Seq[Int] = List(3, 2, 1)

APPEND / PREPEND / CONCAT

  • append는 앞에, prepend는 뒤에
  • :로 끝나는 오퍼레이터는 순서가 뒤바뀜

In [148]:
sequence.:+(4)


Out[148]:
res147: Seq[Int] = List(1, 2, 3, 4)

In [149]:
sequence :+ 4


Out[149]:
res148: Seq[Int] = List(1, 2, 3, 4)

In [150]:
sequence.+:(0)


Out[150]:
res149: Seq[Int] = List(0, 1, 2, 3)

In [151]:
0 +: sequence


Out[151]:
res150: Seq[Int] = List(0, 1, 2, 3)

In [152]:
sequence ++ Seq(4, 5, 6)


Out[152]:
res151: Seq[Int] = List(1, 2, 3, 4, 5, 6)

In [153]:
sequence.map(_.toString)


Out[153]:
res152: Seq[String] = List("1", "2", "3")

In [154]:
sequence.flatMap(x => Seq(x, x + 1))


Out[154]:
res153: Seq[Int] = List(1, 2, 2, 3, 3, 4)

In [155]:
sequence foreach println
// foreach : return 값이 없고 사이드 이펙트!


1
2
3

In [156]:
sequence.foldLeft("")(_ + _ + 1)
// 아래 표현과 동일


Out[156]:
res155: String = "112131"

In [157]:
("" /: sequence)(_ + _ + 1)


Out[157]:
res156: String = "112131"

In [158]:
sequence.foldRight("")(1 + _ + _)


Out[158]:
res157: String = "234"

In [159]:
(sequence :\ "")(1 + _ + _)


Out[159]:
res158: String = "234"

In [161]:
Nil
// nil list


Out[161]:
res160: Nil.type = List()

CONS

  • construct

In [162]:
val list = 1 :: 2 :: 3 :: Nil


Out[162]:
list: List[Int] = List(1, 2, 3)

In [163]:
4 :: 5 :: list


Out[163]:
res162: List[Int] = List(4, 5, 1, 2, 3)

In [ ]:
앞에서 작업을   list 주로 사용

In [ ]:


In [164]:
List(1, 2, 3) ::: List(4, 5, 6)


Out[164]:
res163: List[Int] = List(1, 2, 3, 4, 5, 6)

:::는 리스트끼리 합치고

::는 두개 그냥 합침

패턴 매칭


In [165]:
def map[A, B](list: List[A])(f: A => B): List[B] = list match {
  case Nil => Nil
  case x :: xs => f(x) :: map(xs)(f)
}


Out[165]:
defined function map

INDEXEDSEQ


In [167]:
IndexedSeq(1, 2, 3)


Out[167]:
res166: IndexedSeq[Int] = Vector(1, 2, 3)

In [168]:
import collection.immutable.Queue


Out[168]:
import collection.immutable.Queue

In [169]:
Queue(1, 2, 3)


Out[169]:
res168: Queue[Int] = Queue(1, 2, 3)

RANGE


In [170]:
1 to 10


Out[170]:
res169: Range.Inclusive = Range(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

In [171]:
(1 to 10).toList


Out[171]:
res170: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

In [172]:
(1 to 10 by 2)


Out[172]:
res171: Range = Range(1, 3, 5, 7, 9)

In [173]:
(1 until 10).toList


Out[173]:
res172: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9)

STREAM

  • list랑 거의 같은데, #:: 가 cons
  • 맨 앞의 head 값만 계산하고 뒤의 값들은 계산을 안해둔 상태. lazy!
  • 링크

EXERCISE: RUNLENGTH


In [177]:
def runLength[A](l: List[A]): List[(A, Int)] = l.foldLeft(List.empty[(A, Int)]) { // 빈 리스트인데 타입이 튜플!
    case ((x, n) :: xs, a) if x == a => (x, n + 1) :: xs
    case (acc, a) => (a, 1) :: acc
}.reverse


Out[177]:
defined function runLength

In [178]:
println(runLength("abbbcc".toList))


List((a,1), (b,3), (c,2))

In [179]:
assert(runLength("abbbcc".toList) ==
  List(('a', 1), ('b', 3), ('c', 2))
)

In [180]:
println("abbbcc".toList)


List(a, b, b, b, c, c)

EXERCISE: FIZZBUZZ

  • 유명한 코딩 테스트
  • 3의 배수 fizz
  • 5의 배수 buzz
  • 3,5 배수 동시에 하면 fizz buzz
  • * : variable argument로 숫자를 여러개 넣을 수 있음
  • 숙제

In [ ]:
def fizzBuzz(n: Int)(cond: (Int, String)*): Unit = ???

In [ ]:
fizzBuzz(20)((3, "Fizz"), (5, "Buzz"))