Commit b6e711f0 authored by Haochen Xie's avatar Haochen Xie

add ch3/List.scala

parent 0c18d71e
package name.haochenxie.fpscala.ch3
import scala.annotation.tailrec
sealed trait List[+A]
case object Nil extends List[Nothing]
case class Cons[+A](head: A, tail: List[A]) extends List[A]
object List {
def sum: List[Int] => Int = {
case Nil => 0
case Cons(head, tail) => head + sum(tail)
}
// Exercise 3.2
def tail[A]: List[A] => List[A] = {
case Cons(_, tail) => tail
}
// Exercise 3.3
def setHead[A](newHead: A): List[A] => List[A] = {
case Cons(_, tail) => Cons(newHead, tail)
}
// Exercise 3.4
// Scala sadly cannot make tail recursion transformation for
// curried functions like this..
def drop0[A](n: Int): List[A] => List[A] =
if (n == 0) $=>$ // identity function
else { case Cons(_, tail) => drop0(n-1)(tail) }
@tailrec
def drop[A](n: Int, as: List[A]): List[A] =
if (n == 0) as // identity function
else as match {
case Cons(_, tail) => drop(n-1, tail)
}
// Exercise 3.5
// again, Scala cannot apply tailrec transformation here..
def dropWhile0[A](pred: A => Boolean): List[A] => List[A] = {
case Cons(head, tail) if pred(head) =>
dropWhile0(pred)(tail)
case $@_ => $
}
@tailrec
def dropWhile[A](pred: A => Boolean, as: List[A]): List[A] = as match {
case Cons(head, tail) if pred(head) =>
dropWhile(pred, tail)
case _ => as
}
// Exercise 3.6
def init[A]: List[A] => List[A] = {
case Cons(last2, Cons(last1, Nil)) => Cons(last2, Nil)
case Cons(head, tail) => Cons(head, init(tail))
}
// def foldRight[A,B,C](as: List[A])(i: B)(f: (B, A) => B): B = {
// @tailrec
// def rec(as: List[A], i: B, f: (B, A) => B): B = as match {
// case Nil => i
// case Cons(head, tail) => rec(tail, f(i, head), f)
// }
// rec(as, i, f)
// }
// Exercise 3.10
@tailrec
private def foldLeft0[A, B](as: List[A], i: B, f: (B, A) => B): B = as match {
case Nil => i
case Cons(head, tail) => foldLeft0(tail, f(i, head), f)
}
def foldLeft[A,B,C](as: List[A], i: B)(f: (B, A) => B): B = foldLeft0(as, i, f)
// Exercise 3.13
// although this looks like cheating, we essentially need to build
// a data structure to store all values in the list, so this should
// be considered of one of the best implementations of foldRight using
// foldLeft
def foldRight[A,B,C](as: List[A], i: B)(f: (A, B) => B): B =
foldLeft(reverse(as), i)((x, y) => f(y, x))
// Exercise 3.11, also Exercise 3.9, somehow
def length[A](as: List[A]) = foldLeft(as, 0) { case (n, _) => n + 1 }
// Exercise 3.14
def append[A](as: List[A], bs: List[A]) = foldRight(as, bs)(Cons(_, _))
// Exercise 3.11
def sum1(as: List[Int]) = foldLeft(as, 0)(_+_)
def product1(ints: List[Int]) = foldLeft(ints, 1)(_*_)
// Execise 3.12
def reverse[A](as: List[A]): List[A] = foldLeft(as, Nil: List[A])((l, x) => Cons(x, l))
// Execise 3.15
def flatten[A](ls: List[List[A]]): List[A] = {
@tailrec
def rec(ls: List[List[A]], acc: List[A]): List[A] = ls match {
case Nil => acc
case Cons(Nil, tail) => rec(tail, acc)
case Cons(Cons(a, as), tail) => rec(Cons(as, tail), Cons(a, acc))
}
reverse(rec(ls, Nil))
}
// Execise 3.18
def map[A,B](as: List[A])(f: A => B): List[B] = as match {
case Nil => Nil
case Cons(head, tail) => Cons(f(head), map(tail)(f))
}
// Execise 3.19
def filter[A](as: List[A])(pred: A => Boolean): List[A] = as match {
case Nil => Nil
case Cons(head, tail) =>
if (pred(head)) Cons(head, filter(tail)(pred))
else filter(tail)(pred)
}
// Exercise 3.20
def flatMap[A,B](as: List[A])(f: A => List[B]): List[B] = flatten(map(as)(f))
// Exercise 3.21
def filter2[A](as: List[A])(pred: A => Boolean): List[A] = flatMap(as) {
case a if pred(a) => List(a)
case _ => Nil
}
// Exercise 3.23
def zipWith[A,B,C](as: List[A], bs: List[B])(f: (A, B) => C): List[C] = (as, bs) match {
case (Nil, Nil) => Nil
case (Cons(a, as), (Cons(b, bs))) => Cons(f(a, b), zipWith(as, bs)(f))
}
// Exercise 3.24
def hasSubsequence[A](sup: List[A], sub: List[A]): Boolean = sub match {
case Nil => true
case Cons(first, _) => {
// @tailrec // I hate that @tailrec doesn't work like this..
// // missing the 'function' keyword in OCaml
// def step: (A, List[List[A]], List[List[A]]) => List[List[A]] = {
// case (_, Nil, acc) => acc
// case (a, Cons(Nil, rest), acc) => step(a, rest, acc)
// case (a, Cons(Cons(b, tail), rest), acc) =>
// if (a == b) step(a, rest, Cons(tail, acc))
// else step(a, rest, acc)
// case _ => Nil
// }
@tailrec
def step(a: A, reg: List[List[A]], acc: List[List[A]]): List[List[A]] = (a, reg, acc) match {
case (_, Nil, acc) => acc
case (a, Cons(Nil, rest), acc) => step(a, rest, acc)
case (a, Cons(Cons(b, tail), rest), acc) =>
if (a == b) step(a, rest, Cons(tail, acc))
else step(a, rest, acc)
case _ => Nil
}
@tailrec
def rec(input: List[A], reg: List[List[A]]): Boolean = (input, reg) match {
case (Nil, _) => false
case (Cons(cursor, rest), reg0) => {
val reg1 = if (cursor == first) step(cursor, Cons(sub, reg0), Nil)
else step(cursor, reg0, Nil)
if (filter(reg1)(_ == Nil) != Nil) true
else rec(rest, reg1)
}
}
rec(sup, Nil)
}
}
def apply[A](as: A*): List[A] = {
if (as.isEmpty) Nil
else Cons(as.head, apply(as.tail: _*))
}
}
object ListScratch {
// Exercise 3.1
// answer: it's so trivial..
val x = List(1,2,3,4,5) match {
case Cons(x, Cons(2, Cons(4, _))) => x
case Nil => 42
case Cons(x, Cons(y, Cons(3, Cons(4, _)))) => x + y
case Cons(h, t) => h + List.sum(t)
case _ => 101
}
def main(args: Array[String]) {
println("\n-------------")
println("Exercise 3.1:")
println(x)
println("\n-------------")
println("Exercise 3.5:")
println(List.dropWhile[Int](_ < 2, List(1, 3, 2)))
println("\n-------------")
println("Exercise 3.6:")
println(List.init(List(1, 3, 2)))
// Exercise 3.7
// Exercise 3.8
// skipped..
println("\n-------------")
println("Exercise 3.9:")
println(List.length(List(1, 3, 2)))
println(List.length(List()))
println("\n-------------")
println("Exercise 3.12:")
println(List.reverse(List(1, 3, 2)))
println("\n-------------")
println("Exercise 3.14:")
println(List.append(List(1, 3, 2), List(9, 5, 7)))
println("\n-------------")
println("Exercise 3.15:")
println(List.flatten(List(List(1, 3, 2), List(2, 1), List(), List(9, 5, 7), List(4))))
// Exercise 3.16, 3.17
def ex3_16: List[Int] => List[Int] = List.map(_)(_+1)
def ex3_17: List[Int] => List[String] = List.map(_)(_.toString)
println("\n-------------")
println("Exercise 3.19:")
println(List.filter(List(1, 3, 2))(_ % 2 == 0))
println("\n-------------")
println("Exercise 3.21:")
println(List.filter2(List(1, 3, 2))(_ % 2 == 0))
// Exercise 3.22
def ex3_22(as: List[Int], bs: List[Int]): List[Int] = (as, bs) match {
case (Nil, Nil) => Nil
case (Cons(a, as), Cons(b, bs)) => Cons(a + b, ex3_22(as, bs))
}
println("\n-------------")
println("Exercise 3.24:")
println(List.hasSubsequence(List(1,2,4,2,9), List(4,2,9)))
println(List.hasSubsequence(List(1,2,4,2,9), List(9)))
println(List.hasSubsequence(List(1,2,4,2,9), List()))
println(List.hasSubsequence(List(1,2,4,2,9), List(4,9)))
println(List.hasSubsequence(List(1,2,4,2,9), List(5,1)))
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment