It’s been a while since I thought about Paul Graham’s essay, Revenge of the Nerds, in which he highlighted the advantages Lisp has over other programming languages, or the essay Eric Kidd wrote, Why Ruby is an acceptable LISP, in which he highlighted features of the Ruby language that made it “acceptable” to use as a Lisp replacement.
Wordnik made the transition from Java to Scala before I joined them, and at least in my early days there, it seemed like the question was “Why Scala is a better Java.” For example, Tony Tam (the current CEO, but “A CEO who codes” and the chef overseeing the preparation of our particular technological stew), said that Scala’s traits were a big win for Wordnik (see this report, for example). Traits are an improvement over Java’s interfaces, but not an especially new way of looking at programming.
Scala isn’t as Lisp-like as Clojure, nor is it as pure as Haskell. A lot of work has been done to make Scala more like Haskell, both in the language itself as well as third-party libraries such as scalaz. But, as I have been writing Scala code, especially on a recent series of projects, I’ve come to realize that many of the things that I liked about programming in Lisp are present in Scala, even without going into the deeper ends of Monads, Monoids and Applicatives.
As three examples, consider collections, recursion, and functional counters.
Collections. Most of the code I write seems to work over collections of various types, and the Scala collection is well-thought out. It provides the real workhorses of functional programing (map, flatMap, filter, fold, reduce, take, drop, zip). And the chaining syntax is, I would argue, an improvement over Common Lisp’s s-expressions (so much so that Clojure provides it as well). As a random snippet of code, consider this from something I’m working on right now (similar returns an iterable set of Tuples which contain an object and a score):
similar(fv, minShared). take(n). map(x ⇒ (x._1.vectorKey, x._2)). filter(_._2 > 0.0)
Recursion. I was talking to Stew O’Connor about a particular mess of code I had created, and I was trying to simplify it (there was a hairy fold operation, if I recall, and the line count for the function itself was way too high). His wise suggestion was that I use recursion for what I was doing — I palmfaced myself and told him that they were going to take away my Lisp coder’s card.
I write a lot of code that looks like this:
def selfAndFollowingSiblings: Seq[Element] = {
def recurse(element: Element, elements: ListBuffer[Element]): Seq[Element] =
element match {
case null ⇒ elements.toList
case _ ⇒ recurse(element.nextElementSibling(), elements += element)
}
recurse(element, ListBuffer[Element]())
}
(I apologize for that null; this is a case where I’m using a Java library — the wonderful Jsoup — and it retains its Javaness even when called from Scala). This feels very Lisp-like to me.
Functional counters. I really only mention this because it’s described in Paul Graham’s original essay — how to write a function that generates accumulators; that is, a function (with parameter n) returning a function which, on each invocation, returns the next value of n. To be able to do this, of course, a language needs to support functions as first-level objects. As Graham points out, this is easy in Lisp:
(defun create-counter (n) (lambda (i) (incf n i)))
And it’s not too difficult in Scala:
scala> def createCounter(i:Int = 0) =
{var n = i; () => {n+= 1; n}}
createCounter: (i: Int)() => Int
scala> val counter = createCounter()
counter: () => Int = <function0>
scala> counter()
res0: Int = 1
scala> counter()
res1: Int = 2
scala> val counter2 = createCounter(100)
counter2: () => Int = <function0>
scala> counter2()
res2: Int = 101
scala> counter2()
res3: Int = 102
scala> counter2()
res4: Int = 103
Scala has many other virtues, even if it at times is hampered by its syntax. Scala 2.10 added Lisp-like macros, and I look forward to exploring them, even as I dread what that will be like for a messy language like Scala. But it is its basic functional aspect that I currently like the most. I’m even gaining an appreciation for strong typing.