For day 2 of Scala the book focuses on the functional programming side of things. The first exercise was just a quickie to make a very simple functional style program using foldLeft. The goal was to count the total number of characters in a List of Strings. The foldLeft function takes a starting value and then iterates over a list. Each iteration uses the value returned by the last as its new starting value.

I solved this with both forms of foldLeft, the curried version and the standard (is there another name?).

val strings = List("moo","meow","oink")

//foldLeft can be called on a list in two ways
val length1 = (0 /: strings) {(sum,value) => sum + value.length}
val length2 = strings.foldLeft(0)((sum,value) => sum + value.length)
println("Length1 is " + length1)
println("Length2 is " + length2)

The second exercise was a little bit more complex. The task was to create a Trait called Censor which could be used along with a class to censor specific words in a String using a Map. As an extra bit, load the censor mapping from a file.

import scala.collection.mutable.HashMap

val censorMap = new HashMap[String,String]
for(line <- scala.io.Source.fromFile("censor.txt").getLines) {
  val vals = line.trim().split(",")
  censorMap += vals(0) -> vals(1)
}

val printer = new CensoredPrinter(censorMap)
printer.print("I like to say shoot and darn")

class CensoredPrinter(censorMap: HashMap[String,String]) extends Censor {
  def print(string: String) {
    println(filter2(string, censorMap))
  }
}

trait Censor {
  //not very functional as it is modifying newText over and over
  def filter1(text: String, censorMap: HashMap[String,String]): String = {
    var newText = text
    censorMap.foreach(censor => newText = newText.replaceAll(censor._1, censor._2))
    return newText
  }

  //written in a more functional programming style
  def filter2(text: String, censorMap: HashMap[String,String]): String = {
    //reduceLeft starts on the first element of the list but otherwise
    //seems the same as foldLeft which takes a starting value.
    //with the anonymous array here due to text.split that makes reduceLeft the better option
    //but is there some other difference I haven't caught on to?
    return text.split(" ").reduceLeft((nt,word) => nt + " " + censorMap.getOrElse(word,word))
  }
}

I wasn't 100% happy with this solution. It met the requirements as they were defined and used concepts in the chapter, but I felt there was probably a better solution I would have found if I had more experience with functional programming. For instance with all the focus on immutable values, I felt like my censorMap should be a proper immutable Map and not the mutable version of HashMap. I also used reduceLeft rather than foldLeft even though the chapter has only discussed foldLeft. The difference isn't huge, but I felt that the problem likely had a solution that used foldLeft which was intended to be found.

A quick trip to Google and I found this solution. It uses an immutable map created all in one shot by calling foldLeft on the list of lines returned by getLines when reading the file. The actual censoring bit was also managed using foldLeft on the Map first which allowed replaceAll to be used on the String as I did in my more OO styled method rather than manually iterating over each word in the line as I did in my truly functional method.