Charlie Harvey

Scala — Day Two

It all seemed so straightforward at first. And it was. Until I needed to split an array into key value pairs for the second excercise. I spent about two hours trying to find a nice way f doing that. I’m not entirely happy with the way I came up with, but it works at least.

The scala syntax and especially the type system seemed determined not to let me write something simple as I would in Perl, say my %wordhash = map { split / / } @lines I am sure there is a nice clean way to do it in Scala, but I’ve not found it. Hey ho. Other than that the tasks were fairly straightforward and actually sorta fun. I did find that the syntax felt a little alien to me, and I spent a lot of time battling the type system rather than thinking about my meaning. But I guess that is something that is inevitable when learning a new language.

string_sum.scala

Use foldLeft to compute the total size of a list of strings

I thought that this meant the total length of all the strings in the list of strings. Which is pedantic of me. I rather liked the :/ form of foldLeft. Which probably has something to do with having a Perl background. Here is the code anyhow: $ cat string_sum.scala val words = List ("plinth" , "antediluvian" , "moist" , "recalcitrance" , "flange" , "ashanti" ) val total_length = (0 /: words) { (sum, word) => sum + word.size } println("Total word length is: " + total_length) Running this code gives me: $ scala string_sum.scala Total word length is: 49 Is that right? I’ll use a bit of perl and bash to check: $ cat string_sum.scala | perl -ne 'next unless /"/; next if /Total/; s/.*"([^"]+)"/$1/; s/[\r\n]//g; print' | wc -c 49 Super. Job done.

censor.scala

  • Write a Censor trait with a method that will replace the curse words Shoot and Darn with Pucky and Beans alternatives. Use a map to store the curse words and their alternatives.
  • Load the curse words and alternatives from a file

I think my implementation is OK, though the k->v splitting felt kludgey to me and the CensoredWords class doesn't seem totally necessary. Traits are a good thing, so I’m glad of having had the chance to hack one. trait Censor { val badWordFile = "badwords.txt" var badWords = Map( "shoot" -> "pucky", "darn" -> "beans" ) // passed a List of words // return censored word list def censorList (wordList: List[String]): List[String] = { // using the ternary-like construct again and filter as described in the book // also contains method as per http://www.scala-lang.org/api/current/scala/collection/immutable/Map.html wordList.map(word => if(badWords.contains(word)) badWords(word) else word ) } // passed a String to censor // returns a censored String def censorString (wordString: String): String = { // I used split(" ").toList() to split the String into a list. Not sure toList is necessary. // and mkString to rejoin the censored list returned by CensorList // (cf: http://www.scala-lang.org/api/2.7.5/scala/Iterable.html#mkString(String)) // Scala has a perlish implicit return so I rely on that to return censorList(List.fromArray(wordString.split(" "))).mkString(" ") } // Read badwords from badWordFile def readBadWordsFromFile() { // hints on Map from http://langref.org/scala/maps var badWordMap = Map.empty[String,String] val lines = scala.io.Source.fromFile(badWordFile).getLines // This was physically painful to write, tried about a million approaches. // It still feels kludgey and not elegant. lines.foreach( line => { line.split(" ") match { case Array(k,v) => { badWordMap += k -> v.trim } } } ) badWords = badWordMap } } class Words(val data: String) { def getData(): String = { data } } class CensoredWords(override val data: String) extends Words(data) with Censor { def getPolite(): String = { readBadWordsFromFile() censorString(data) } } val c=new CensoredWords("I want to shoot the motherfucker.") println(c.getPolite()) As you can probably spot I have a badwords.txt text file with the following in it as the data source: $ cat badwords.txt shoot pucky darn beans

Well, an interesting day and a good illustration of some functional constructs. If it hadn't been for wrestling with the syntax and the type system it would have been even funner.


Comments

  • Be respectful. You may want to read the comment guidelines before posting.
  • You can use Markdown syntax to format your comments. You can only use level 5 and 6 headings.
  • You can add class="your language" to code blocks to help highlight.js highlight them correctly.

Privacy note: This form will forward your IP address, user agent and referrer to the Akismet, StopForumSpam and Botscout spam filtering services. I don’t log these details. Those services will. I do log everything you type into the form. Full privacy statement.