// Scala Lecture 3//=================// One of only two places where I conceded to mutable// data structures: The following function generates // new labelsvar counter = -1def fresh(x: String) = { counter += 1 x ++ "_" ++ counter.toString()}fresh("x")fresh("x")// this can be avoided, but would have made my code more// complicated// Tail recursion//================def my_contains(elem: Int, lst: List[Int]): Boolean = lst match { case Nil => false case x::xs => if (x == elem) true else my_contains(elem, xs)}my_contains(4, List(1,2,3))my_contains(2, List(1,2,3))my_contains(1000000, (1 to 1000000).toList)my_contains(1000001, (1 to 1000000).toList)//factorial V0.1import scala.annotation.tailrecdef fact(n: Long): Long = if (n == 0) 1 else n * fact(n - 1)fact(10000) // produces a stackoverflow@tailrecdef factT(n: BigInt, acc: BigInt): BigInt = if (n == 0) acc else factT(n - 1, n * acc)println(factT(10000, 1))// the functions my_contains and factT are tail-recursive // you can check this with import scala.annotation.tailrec// and the annotation @tailrec// for tail-recursive functions the scala compiler// generates loop-like code, which does not need// to allocate stack-space in each recursive// call; scala can do this only for tail-recursive// functions// consider the following "stupid" version of the// coin exchange problem: given some coins and a// total, what is the change can you get?val coins = List(4,5,6,8,10,13,19,20,21,24,38,39,40)def first_positive[B](lst: List[Int], f: Int => Option[B]): Option[B] = lst match { case Nil => None case x::xs => if (x <= 0) first_positive(xs, f) else { val fx = f(x) if (fx.isDefined) fx else first_positive(xs, f) }}import scala.annotation.tailrecdef search(total: Int, coins: List[Int], cs: List[Int]): Option[List[Int]] = { if (total < cs.sum) None else if (cs.sum == total) Some(cs) else first_positive(coins, (c: Int) => search(total, coins, c::cs))}search(11, coins, Nil)search(111, coins, Nil)search(111111, coins, Nil)val junk_coins = List(4,-2,5,6,8,0,10,13,19,20,-3,21,24,38,39, 40)search(11, junk_coins, Nil)search(111, junk_coins, Nil)import scala.annotation.tailrec@tailrecdef searchT(total: Int, coins: List[Int], acc_cs: List[List[Int]]): Option[List[Int]] = acc_cs match { case Nil => None case x::xs => if (total < x.sum) searchT(total, coins, xs) else if (x.sum == total) Some(x) else searchT(total, coins, coins.filter(_ > 0).map(_::x) ::: xs)}val start_acc = coins.filter(_ > 0).map(List(_))searchT(11, junk_coins, start_acc)searchT(111, junk_coins, start_acc)searchT(111111, junk_coins, start_acc)// Moral: Whenever a recursive function is resource-critical// (i.e. works with large recursion depths), then you need to// write it in tail-recursive fashion.// // Unfortuantely, the Scala is because of current limitations in // the JVM not as clever as other functional languages. It can // only optimise "self-tail calls". This excludes the cases of // multiple functions making tail calls to each other. Well,// nothing is perfect. // Polymorphic Types//===================// You do not want to write functions like contains, first // and so on for every type of lists.def length_string_list(lst: List[String]): Int = lst match { case Nil => 0 case x::xs => 1 + length_string_list(xs)}length_string_list(List("1", "2", "3", "4"))def length[A](lst: List[A]): Int = lst match { case Nil => 0 case x::xs => 1 + length(xs)}def map_int_list(lst: List[Int], f: Int => Int): List[Int] = lst match { case Nil => Nil case x::xs => f(x)::map_int_list(xs, f) }map_int_list(List(1, 2, 3, 4), square)// Remember?def first[A, B](xs: List[A], f: A => Option[B]): Option[B] = ...// polymorphic classes//(trees with some content)abstract class Tree[+A]case class Node[A](elem: A, left: Tree[A], right: Tree[A]) extends Tree[A]case object Leaf extends Tree[Nothing]val t0 = Node('4', Node('2', Leaf, Leaf), Node('7', Leaf, Leaf))def insert[A](tr: Tree[A], n: A): Tree[A] = tr match { case Leaf => Node(n, Leaf, Leaf) case Node(m, left, right) => if (n == m) Node(m, left, right) else if (n < m) Node(m, insert(left, n), right) else Node(m, left, insert(right, n))}// the A-type needs to be orderedabstract class Tree[+A <% Ordered[A]]case class Node[A <% Ordered[A]](elem: A, left: Tree[A], right: Tree[A]) extends Tree[A]case object Leaf extends Tree[Nothing]def insert[A <% Ordered[A]](tr: Tree[A], n: A): Tree[A] = tr match { case Leaf => Node(n, Leaf, Leaf) case Node(m, left, right) => if (n == m) Node(m, left, right) else if (n < m) Node(m, insert(left, n), right) else Node(m, left, insert(right, n))}val t1 = Node(4, Node(2, Leaf, Leaf), Node(7, Leaf, Leaf))insert(t1, 3)val t2 = Node('b', Node('a', Leaf, Leaf), Node('f', Leaf, Leaf))insert(t2, 'e')// Regular expressions - the power of DSLs in Scala//==================================================abstract class Rexpcase object ZERO extends Rexpcase object ONE extends Rexpcase class CHAR(c: Char) extends Rexpcase class ALT(r1: Rexp, r2: Rexp) extends Rexp // alternative r1 + r2case class SEQ(r1: Rexp, r2: Rexp) extends Rexp // sequence r1 r2 case class STAR(r: Rexp) extends Rexp // star r*// (ab)*val r0 = STAR(SEQ(CHAR('a'), CHAR('b')))// some convenience for typing in regular expressionsimport scala.language.implicitConversions import scala.language.reflectiveCalls def charlist2rexp(s: List[Char]): Rexp = s match { case Nil => ONE case c::Nil => CHAR(c) case c::s => SEQ(CHAR(c), charlist2rexp(s))}implicit def string2rexp(s: String): Rexp = charlist2rexp(s.toList)val r1 = STAR("ab")val r2 = STAR("")val r3 = STAR(ALT("ab", "baa baa black sheep"))implicit def RexpOps (r: Rexp) = new { def | (s: Rexp) = ALT(r, s) def % = STAR(r) def ~ (s: Rexp) = SEQ(r, s)}implicit def stringOps (s: String) = new { def | (r: Rexp) = ALT(s, r) def | (r: String) = ALT(s, r) def % = STAR(s) def ~ (r: Rexp) = SEQ(s, r) def ~ (r: String) = SEQ(s, r)}val digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"val sign = "+" | "-" | ""val number = sign ~ digit ~ digit.% // Lazyness with style//=====================// The concept of lazy evaluation doesn’t really exist in // non-functional languages, but it is pretty easy to grasp. // Consider first def square(x: Int) = x * xsquare(42 + 8)// this is called strict evaluationdef expensiveOperation(n: BigInt): Boolean = expensiveOperation(n + 1) val a = "foo"val b = "bar"val test = if ((a == b) || expensiveOperation(0)) true else false// this is called lazy evaluation// you delay compuation until it is really // needed; once calculated though, does not // need to be re-calculated// a useful example isdef time_needed[T](i: Int, code: => T) = { val start = System.nanoTime() for (j <- 1 to i) code val end = System.nanoTime() ((end - start) / i / 1.0e9) + " secs"}// streams (I do not care how many)// primes: 2, 3, 5, 7, 9, 11, 13 ....def generatePrimes (s: Stream[Int]): Stream[Int] = s.head #:: generatePrimes(s.tail filter (_ % s.head != 0))val primes: Stream[Int] = generatePrimes(Stream.from(2))primes.take(10).toListprimes.filter(_ > 100).take(2000).toListtime_needed(1, primes.filter(_ > 100).take(2000).toList)time_needed(1, primes.filter(_ > 100).take(2000).toList)// streams are useful for implementing search problems ;o)// The End//=========// A function should do one thing, and only one thing.// Make your variables immutable, unless there's a good // reason not to.// You can be productive on Day 1, but the language is deep.// I like best about Scala that it lets me write// concise, readable code