Introduction To Scala — Part3 — Tuples, Lists and Polymorphism
/**
* Exercise 3.1 Suppose you are implementing a relational employee database,
* where the database is a list of tuples name * phone * salary:
*
* val db = ("John", "x3456", 50.1) :: ("Jane", "x1234", 107.3) ::
("Joan", "unlisted", 12.7) :: Nil
*
* 1. Write a function find_salary : string -> float that returns the salary
* of an employee, given the name.
*
* 2. Write a general function
*
* select : (string * string * float -> bool) -> (string * string * float) list
*
* that returns a list of all the tuples that match the predicate. For example
* the expression select (fun (_, _, salary) -> salary < 100.0) would return
* the tuples for John and Joan.
*
*/
val db = ("John", "x3456", 50.1) :: ("Jane", "x1234", 107.3) ::
("Joan", "unlisted", 12.7) :: Nil
// to sintetise the code
type listOfTuples = List[(String, String, Double)]
// 1 Write a function find_salary : string -> float that returns the salary
// of an employee, given the name.
def find_salary(name: String) = {
def search(t: listOfTuples): Double = t match {
case (name_, _, salary) :: t if name == name_ => salary
case _ :: t => search(t)
case Nil =>
throw new Exception("Invalid Argument in find_salary")
}
search(db)
}
// Write a general function
// select : (string * string * float -> bool) -> (string * string * float) list
// that returns a list of all the tuples that match the predicate. For example
// the expression select (fun (_, _, salary) -> salary < 100.0) would return
// the tuples for John and Joan.
def select(pred: (String, String, Double) => Boolean) = {
def search(found: listOfTuples): listOfTuples = found match {
case (p1, p2, p3) :: t if pred(p1, p2, p3) => (p1, p2, p3) :: search(t)
case (p1, p2, p3) :: t if !pred(p1, p2, p3) => search(t)
case Nil => Nil
case _ => throw new Exception("Invalid Argument in select function")
}
search(db)
}
// tests
println("Searching the salary of 'Joan' at db: " + find_salary("Joan"))
println("")
val predicate = (_:String, _:String, salary:Double) => (salary < 100.0)
println("All employees that match with predicate 'salary < 100.0': ")
println("\t" + select(predicate) + "\n")
/**
* Exercise 3.2 The function append : ’a list -> ’a list -> ’a list appends two
* lists. It can be defined as follows:
*
* def append(l1: List[A], l2: List[A]): List[A] = l1 match {
* case h :: t => h :: append(t, l2)
* case Nil => l2
* }
*
* Write a tail-recursive version of append.
*/
def append(l1: List[_], l2: List[_]): List[_] = l1 match {
case h :: t => h :: append(t, l2)
case Nil => l2
}
def appendTR(l1: List[_], l2: List[_]) = {
def iter(l: List[_], ll: List[_]): List[_] = ll match {
case h :: ll => iter(h :: l, ll)
case Nil => l
}
iter(l2, l1.reverse)
}
// tests
val l1 = 1 :: 2 :: 3 :: 4 :: Nil
val l2 = 6 :: 7 :: 8 :: Nil
println("Append of " + l1 + " + " + l2 + " = " + append(l1, l2))
println("Tail Recursive of " + l1 + " + " + l2 + " = " + appendTR(l1, l2))
/**
* Exercise 3.3. It is known that a welfare crook lives in Los Angeles.
* You are given lists for
*
* 1) people receiving welfare,
* 2) Hollywood actors, and
* 3) residents of Beverly Hills.
*
* The names in each list are sorted alphabetically (by < ). A welfare crook is
* someone who appears in all three lists. Write an algorithm to find at least
* one crook.
*/
def findCrook(people: List[String], actors: List[String],
residents: List[String]): List[String] =
(people, actors, residents) match {
((ph :: pt), (ah :: at), (rh :: rt)) =>
if (ph < ah || ph < rh) findCrook(pt, ah, rh)
else if (ah < ph || ah < rh) findCrook(ph, at, rh)
else if (rh < ph || rh < ah) findCrook(ph, ag, rt)
else ph
_ => throw new Exception("Invalid Argument in findCrook")
}