Whorfianism in PL design

While the aptness of the Whorfian hypothesis is still a highly-contentious issue when it comes to natural languages, the hypothesis more or less confirms itself again and again in the realms of programming languages. Certain programming styles are simply more suited to certain languages: you don’t try to use higher-order functions in C, after all; the lack of nested functions make this idea unworkable.

Which makes languages like Scala exciting. It’s fully functional, and also fully object-oriented.Integers are objects. Functions? Also objects. The List ADT familiar to functional programmer is now an Object, with methods such as fold and filter defined on it (which makes the syntax a bit confusing, but not if you come from Ruby. Or your first language is japanese. But I digress)

Best of both worlds? Well, not quite. The new Scala compiler looks promising, but it still trips up on this simple mutual-recursion example:

object RecEvenOdd {
  def rec_oddp(n: Int): Boolean =
    { if (n == 0) false else rec_evenp(n-1) }
  def rec_evenp(n: Int): Boolean =
    { if (n == 0 ) true else rec_oddp(n-1) }
  def rec_oddevenp(flag: Boolean, n: Int): Boolean = {
    if (n == 0) flag else rec_oddevenp(!flag, n-1)

  def main(args: Array[String]): unit = {
    val n: Int = Integer.parseInt(args(0));
    System.out.println("recursive: " + n + ": " +       rec_oddevenp(true, n));
    System.out.println("mutual rec: " + n + ": " +       rec_evenp(n));

The former gets detected as a tail call and optimized. The second? No such luck.. yet.

Of further note is the implementation of streams: Scala implements the “odd” style of lazy programming (Wadler et al., How to add laziness to a strict language without even being odd); the provided implementation is very similar to the reference implementation of streams for Scheme in SICP. The following program will thus unnecessarily compute the square root of -1:

object WadlerTest {
  def countdown(n: Int): Stream[Int] =
    Stream.cons(n, countdown(n-1));
  def sqrt(n: Double): Double = {
    System.out.println("sqrt: called with " + n);
  def main(args: Array[String]): unit = {
    countdown(4) map { n => sqrt(n) } take(5) print

The syntax can also be bizarre at times, a motley of Java-isms and proper FP style. For example,

{ n => sqrt(n) }

is η-reducible to sqrt, but Scala would not compile it with this definition of sqrt. Rewriting sqrt thus:

  def sqrt = { n: Double =>

now sqrt can be passed to map – but the automatic cast from Int to Double is no longer performed. Eek.

Moral of the story? I’m learning Haskell.