ababup1192
1/6/2017 - 4:35 PM

ABList.scala

sealed trait ABList[+T] {
  def *:[U >: T](x: U): ABList[U] = new *:(x, this)
  def map[U](f: T => U): ABList[U]
  def foldLeft[Z](z: Z)(f: (Z, T) => Z): Z = z
  def foldRight[Z](z: Z)(f: (T, Z) => Z): Z = z
  def reduceLeft[Z](f: (Z, T) => Z): Z = sys.error("Nil.reduceLeft")
}

case object ABNil extends ABList[Nothing] {
  override def toString: String = "ABList()"
  override def map[U](f: _ => U): ABList[U] = this
}

case class *:[+T](x: T, xs: ABList[T]) extends ABList[T] {
  private def flip[A, B, C](f: A => B => C)(x: B)(y: A) = f(y)(x)

  override def toString = s"ABList(${mkString(", ")})"

  override def map[U](f: T => U): ABList[U] = {
    foldRight(ABList[U]())((x, acc) => f(x) *: acc)
  }

  override def foldLeft[Z](z: Z)(f: (Z, T) => Z): Z = {
    xs match {
      case ABNil => f(z, x)
      case _     => xs.foldLeft(f(z, x))(f)
    }
  }

  override def foldRight[Z](z: Z)(f: (T, Z) => Z): Z = {
    xs match {
      case ABNil => f(x, z)
      case _     => f(x, xs.foldRight(z)(f))
    }
  }

  override def reduceLeft[Z](f: (Z, T) => Z): Z = {
    (xs foldLeft[Z] x)(f)
  }

  def mkString(delimiter: String): String = {
    reduceLeft[String](_ + delimiter + _)
  }
}

object ABList {
  def apply[T](as: T*): ABList[T] = if(as.isEmpty) ABNil else *:(as.head, apply(as.tail: _*))
}

object Main extends App {
  val list: ABList[Int] = 1 *: 2 *: 3 *: ABNil
  println(list.foldLeft(0)(_ + _))
  println(list.toString)
}