Monday, May 28, 2007

Number Parsing in a "Functional" Style

A few days ago David Pollak did a blog showing the differences between a simple function to parse a string and return a number written in Scala in an "imperitive style" and in a "functional style." I commend the post and think many more like it are needed. It is very difficult for a person accustomed to imperitive programming to think in a functional way, and without simple examples comparing the code for common programming tasks, I think most programmers loose patience with functional programming. That all being said, I don't like David's example functional function:

  1. I think the conversion of the string to a list obfuscates what the function is doing, not to mention consumes resources unnecessarily.
  2. I find his use of pattern matching confusing, especially the way list operations are mixed in with it. I spent more time than I willing to admit trying to make sense of it.
  3. His nested function, p, has too many parameters.
So, being that criticism of code without code in return tends to be rather pointless, here's my attempt at the function. I obviously like it better, but I'm neither as familiar with functional programming nor as familiar with Scala as David is.
object Parsely {
 def erikParseNumber(in: String): (Long, Int) = {
   if (in eq null) (0L, 0)
   else {
     val tin = in.trim()
     if (tin.length == 0) (0L, 0)
     else {
       val sign = if (tin.charAt(0) == '-') -1L else 1L
       def p(cur: Long, pos: Int): (Long, Int) = {
         if (pos == tin.length || !tin.charAt(pos).isDigit) (cur * sign, pos)
         else p((cur * 10L) + tin.charAt(pos).toLong - '0'.toLong, pos + 1)
       }
       p(0L, if (tin.charAt(0) == '-' || tin.charAt(0) == '+') 1 else 0)
     }
   }
 }
}
So I've done the following:
  1. I'm using the "pos" parameter as an index into the string, instead of making a list.
  2. In the nested function, I'm accessing some of the values from the enclosing scope instead of passing them as parameters. This reduces the number of parameters from 4 to 2.
  3. I'm using if/else expressions instead of pattern matching
So what do you think? I find my version more readable, and I think it is a little more efficient. However, I haven't tested it much, so maybe there's a bug. If so, please point it out and I'll fix it.

Sphere: Related Content

2 comments:

Burak Emir said...

agree that nested functions are better, and conversion to list is sometimes debatable. but David is right that pattern matching is cool. My (slightly mutilated) code on scala-kurz.org

Erik Engbrecht said...

I like it. I am using pattern matching more as I gain more experience with the language. It does clarify a lot of code.