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]:
In [4]:
    
val l = LinkedList(1, 2, 3,4, 5)
println(l)
    
    
    Out[4]:
In [4]:
    
// GET 함수 구현
def get(n: Int): Maybe[A] = ???
    
    
    
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]:
In [9]:
    
val l = LinkedList(1, 2, 3, 4, 5)
assert(l.get(0) == Just(1))
assert(l.get(6) == Empty)
println("ok!")
    
    
    Out[9]:
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]:
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!")
    
    
    Out[23]:
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]:
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!")
    
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]:
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]:
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!")
    
    
    Out[48]:
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]:
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!")
    
    
    Out[45]:
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]:
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!")
    
    
    Out[43]:
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]:
In [38]:
    
val l = LinkedList(1, 2, 3, 4, 5)
    
    Out[38]:
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!")
    
    
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]:
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!")
    
    
    Out[40]:
In [ ]:
    
    
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]:
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!")
    
    
    Out[50]:
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]:
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!")
    
    
    Out[54]:
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]:
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!")
    
    
    Out[56]:
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]:
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!")
    
    
    Out[58]:
In [59]:
    
def sum(f: Int => Int)(a: Int, b: Int) = (a to b map f).sum
    
    Out[59]:
In [61]:
    
sum(x => x * x)(1, 10)
// 1부터 10까지의 합
    
    Out[61]:
In [62]:
    
sum(_ * 2)(1, 10)
    
    Out[62]:
In [63]:
    
def f(a: Int, b: Int): Int = a * b
    
    Out[63]:
In [64]:
    
def g(a: Int)(b: Int): Int = a * b
    
    Out[64]:
In [65]:
    
f(2, 3)
    
    Out[65]:
In [66]:
    
g(2)(3)
    
    Out[66]:
In [67]:
    
sum(g(2))(1,10)
    
    Out[67]:
In [68]:
    
val pair = ("ans", 42)
    
    Out[68]:
In [71]:
    
val (label, value) = pair
    
    Out[71]:
In [70]:
    
pair._1
    
    Out[70]:
In [72]:
    
pair._2
    
    Out[72]:
In [72]:
    
pair._0
    
    
    
In [73]:
    
val List(a, b, c) = List(1, 2, 3)
    
    Out[73]:
In [74]:
    
val Array(a, b, c) = "1 2 3" split ' '
    
    Out[74]:
In [75]:
    
1 to 10
    
    Out[75]:
In [76]:
    
1 until 10
    
    Out[76]:
In [77]:
    
1 to 10 by 3
    
    Out[77]:
In [78]:
    
6 to 1 by -2
    
    Out[78]:
In [79]:
    
1.to(10)
    
    Out[79]:
In [81]:
    
val aaa = Seq(1, 1, 2, 2, 3, 3)
    
    Out[81]:
In [83]:
    
Set(1, 1, 2, 2, 3, 3)
    
    Out[83]:
In [84]:
    
IndexedSeq(1, 2, 3)
    
    Out[84]:
In [85]:
    
IndexedSeq(1, 2, 3) :+ 4
    
    Out[85]:
In [86]:
    
0 +: IndexedSeq(1, 2, 3)
    
    Out[86]:
In [87]:
    
List(1, 2, 3)
    
    Out[87]:
In [88]:
    
1::(2::(3::Nil))
    
    Out[88]:
In [89]:
    
1::2::3::Nil
    
    Out[89]:
In [90]:
    
Nil.::(3).::(2).::(1)
    
    Out[90]:
In [91]:
    
val (xs, ys) = (List(1, 1, 2, 2, 3, 3), IndexedSeq(1, 2, 3))
    
    Out[91]:
In [92]:
    
xs.head
    
    Out[92]:
In [93]:
    
xs.tail
    
    Out[93]:
In [94]:
    
ys.last
    
    Out[94]:
In [95]:
    
ys.init
    
    Out[95]:
In [96]:
    
ys.head
    
    Out[96]:
In [97]:
    
xs take 4
    
    Out[97]:
In [98]:
    
xs drop 4
    
    Out[98]:
In [99]:
    
ys(1)
    
    Out[99]:
In [100]:
    
xs ++ ys
    
    Out[100]:
In [101]:
    
xs
    
    Out[101]:
In [102]:
    
ys
    
    Out[102]:
In [103]:
    
ys ++ xs
    
    Out[103]:
In [103]:
    
// 앞의 자료형을 따라감
    
In [104]:
    
xs.reverse
    
    Out[104]:
In [105]:
    
ys updated(1, 10)
    
    Out[105]:
In [106]:
    
ys
    
    Out[106]:
In [107]:
    
xs indexOf 3
    
    Out[107]:
In [108]:
    
xs contains 3
    
    Out[108]:
In [109]:
    
xs contains 4
    
    Out[109]:
In [110]:
    
xs zip ys
    
    Out[110]:
In [111]:
    
ys zip xs
    
    Out[111]:
In [112]:
    
xs.sum
    
    Out[112]:
In [113]:
    
xs.product
    
    Out[113]:
In [114]:
    
xs
    
    Out[114]:
In [115]:
    
xs.max
    
    Out[115]:
In [116]:
    
xs.min
    
    Out[116]:
In [117]:
    
xs filter (x => x%2 == 0)
    
    Out[117]:
In [118]:
    
xs filterNot (x => x%2 ==0)
    
    Out[118]:
In [119]:
    
xs filter (_%2 == 0)
    
    Out[119]:
In [120]:
    
xs partition (_%2 == 0)
    
    Out[120]:
In [121]:
    
xs takeWhile (_%3 > 0)
    
    Out[121]:
In [122]:
    
xs
    
    Out[122]:
In [123]:
    
xs dropWhile (_%3 > 0)
    
    Out[123]:
In [124]:
    
xs span (_%3 > 0)
    
    Out[124]:
In [125]:
    
xs map (x => x * 2)
    
    Out[125]:
In [131]:
    
xs map square
    
    
    
In [126]:
    
xs groupBy (_ % 2)
    
    Out[126]:
In [128]:
    
xs.reduceLeft((acc, x) => acc + x)
    
    Out[128]:
In [129]:
    
xs.foldLeft(10)((acc, x) => acc + x)
    
    Out[129]:
In [130]:
    
xs.foldLeft(10)(_ + _)
    
    Out[130]:
In [131]:
    
(10 /: xs)(_ + _)
    
    Out[131]:
In [132]:
    
val sequence = Seq(1, 2, 3)
    
    Out[132]:
In [133]:
    
sequence.apply(0)
    
    Out[133]:
In [134]:
    
sequence(0)
    
    Out[134]:
In [135]:
    
sequence(3)
    
    
In [137]:
    
sequence(-1)
// - dksehlsp
    
    
In [138]:
    
sequence.head
    
    Out[138]:
In [139]:
    
sequence.tail
    
    Out[139]:
In [141]:
    
sequence.headOption
// exception을 안 일으키고 작성 가능
    
    Out[141]:
In [142]:
    
sequence.length
    
    Out[142]:
In [143]:
    
sequence.contains(2)
    
    Out[143]:
In [144]:
    
sequence.find(_ == 3)
    
    Out[144]:
In [145]:
    
sequence.find(_ > 4)
    
    Out[145]:
In [146]:
    
sequence.filter(_ > 1)
    
    Out[146]:
In [147]:
    
sequence.sortWith(_ >  _)
    
    Out[147]:
In [148]:
    
sequence.:+(4)
    
    Out[148]:
In [149]:
    
sequence :+ 4
    
    Out[149]:
In [150]:
    
sequence.+:(0)
    
    Out[150]:
In [151]:
    
0 +: sequence
    
    Out[151]:
In [152]:
    
sequence ++ Seq(4, 5, 6)
    
    Out[152]:
In [153]:
    
sequence.map(_.toString)
    
    Out[153]:
In [154]:
    
sequence.flatMap(x => Seq(x, x + 1))
    
    Out[154]:
In [155]:
    
sequence foreach println
// foreach : return 값이 없고 사이드 이펙트!
    
    
In [156]:
    
sequence.foldLeft("")(_ + _ + 1)
// 아래 표현과 동일
    
    Out[156]:
In [157]:
    
("" /: sequence)(_ + _ + 1)
    
    Out[157]:
In [158]:
    
sequence.foldRight("")(1 + _ + _)
    
    Out[158]:
In [159]:
    
(sequence :\ "")(1 + _ + _)
    
    Out[159]:
In [161]:
    
Nil
// nil list
    
    Out[161]:
In [162]:
    
val list = 1 :: 2 :: 3 :: Nil
    
    Out[162]:
In [163]:
    
4 :: 5 :: list
    
    Out[163]:
In [ ]:
    
앞에서 작업을 할 때 list 주로 사용
    
In [ ]:
    
    
In [164]:
    
List(1, 2, 3) ::: List(4, 5, 6)
    
    Out[164]:
:::는 리스트끼리 합치고
::는 두개 그냥 합침
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]:
In [167]:
    
IndexedSeq(1, 2, 3)
    
    Out[167]:
In [168]:
    
import collection.immutable.Queue
    
    Out[168]:
In [169]:
    
Queue(1, 2, 3)
    
    Out[169]:
In [170]:
    
1 to 10
    
    Out[170]:
In [171]:
    
(1 to 10).toList
    
    Out[171]:
In [172]:
    
(1 to 10 by 2)
    
    Out[172]:
In [173]:
    
(1 until 10).toList
    
    Out[173]:
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]:
In [178]:
    
println(runLength("abbbcc".toList))
    
    
In [179]:
    
assert(runLength("abbbcc".toList) ==
  List(('a', 1), ('b', 3), ('c', 2))
)
    
In [180]:
    
println("abbbcc".toList)
    
    
In [ ]:
    
def fizzBuzz(n: Int)(cond: (Int, String)*): Unit = ???
    
In [ ]:
    
fizzBuzz(20)((3, "Fizz"), (5, "Buzz"))