// This worksheet demonstrates Scala's support for first class functions.
// The name 'f' is being bound to a function literal (also called a lambda term). The function
// itself is anonymous, but the name 'f' refers to it so it can be used as 'f' in following
// code. The body of the lambda is a single expression but in Scala that isn't much of a
// restriction.
//
val f = (x: Int) => x + 1
// Notice that function types are showing with the => but method types are not. Methods differ
// from functions only in that a method is always used in conjunction with some particular
// object. The Scala compiler converts methods to functions (really closures) automatically.
//
def g(x: Int) = x + 1
// Higher order methods/functions are methods/functions that take functions as parameters or
// that return functions as results. The workWith method below is such a method. It is
// parameterized by an "action" (that is, a function) that allows its behavior to be
// customized.
//
def workWith(value: Int, thing: Int => Int): Int = {
// The method just calls the given function with the given value. That's not very exciting
// but a more interesting method would do more.
//
thing(value)
}
// A generic filter method processes a list and selects only the elements that satisfy the
// given predicate. By using different predicates, different effects can be achieved.
//
def filter[A](myList: List[A], pred: A => Boolean): List[A] =
myList match {
case Nil => List()
case head :: tail =>
if (pred(head))
head :: filter(tail, pred)
else
filter(tail, pred)
}
// Here is a simple method that can be used as a filter predicate.
def isEven(n: Int) = n % 2 == 0
// Technically the method is converted to a function here.
filter(List(1, 2, 3, 4), isEven)
// It is possible to just use a lambda term instead of a separate, named method
filter(List(1, 2, 3, 4), (n: Int) => n % 2 == 0)
// Here is a simple method that can be used as a map transformer.
def doStuff(n: Int) = n.toString
// Use of the library map method.
List(1, 2, 3).map(doStuff)
// Or just...
List(1, 2, 3) map doStuff
// Returns the smallest f such that f > 1 and f <= n where f divides n evenly.
def findFirstFactor(n: Int): Int = {
def firstFactorFrom(start: Int, n: Int): Int =
if (n % start == 0) start else firstFactorFrom(start + 1, n)
firstFactorFrom(2, n)
}
// Returns true if n is prime and false otherwise.
def isPrime(n: Int): Boolean = findFirstFactor(n) == n
// Returns a list of n's prime factors.
// For example, factor(12) returns List(2, 2, 3).
//
def factor(n: Int): List[Int] = {
val firstFactor = findFirstFactor(n)
if (firstFactor == n) List(firstFactor) else firstFactor :: factor(n/firstFactor)
}
val someList = List(1, 2, 3, 4, 5)
val someOtherList = List(10, 100, 1000)
val someThirdList = List(1, 2, 3, 4)
// Some examples of higher order methods in the Scala library. Note the highly abbreviated
// way in which the lambda terms are written. Simple examples can be very concise.
//
someList.dropWhile( _ < 3 )
someList.forall( _ != 0 )
// Computes all primes between 1 and 20 by filtering a range using the isPrime method as a
// predicate.
//
val primes = Range(1, 20) filter { isPrime }
// Mapping factor across the list produces a list of lists in this case.
someOtherList map { factor }
// Flat mapping factor across the list produces a flatted list of factors.
someOtherList flatMap { factor }
// Example folds that collapse a list by combining each element into a running accumulator.
// Notice that foldLeft has two argument lists. This is necessary for type inference to
// work smoothly in this case. The generic types inferred by processing the first argument
// list can be used when analyzing the second argument list (with the lambda).
//
someThirdList.foldLeft(0)( _ + _ )
someThirdList.foldLeft(1)( _ * _ )
// The deOption method unpacks a list of options. Items in the list that are None are removed.
// For example given:
//
// List(Some(5), None, None, Some(-10))
//
// the deOption method returns: List(5, -10)
//
def deOption(values: List[Option[Int]]): List[Int] =
values filter { _.isDefined } map { _.get }