Posts Tagged ‘Perl’
Scala: Post-Functional, Post-Modern, or Just Perl++? March 6, 2010 | 10:30 pm

Let’s start with some background.

I complained that Scala did not seem to be very functional to me, but I didn’t really know how best to express what was fundamentally wrong with it. I did know that if “functional languages have a fixed set of features” like Scala’s creator, Odersky, claims, then it wasn’t simply “first-class functions in there, function literals, closures”, “types, generics, [and] pattern matching”. Scala has missed the functional boat in some basic way.

After a kerfuffle in the comments, Brian enlightened us all by telling us what is a functional programming language. His explanation (while being a self-admitted generalization) is summarized as follows:

So, what is it that differentiates the functional programming languages from all the other programming languages? It is simply this: the functional programming languages use, as their fundamental model of computation, the lambda calculus, while all the other programming languages use the Turing machine as their fundamental model of computation.

Six months later, Odersky responds with a very interesting post, which actually agrees that Scala is not a functional language in Brian’s sense, but instead argues that any language is functional if it “makes programming centered around functions easy and natural”. He then runs through a list of features which is in common with functional languages, noting that Scala has them within handwave enough (more on that later). He ends wishing that people would “stop thinking of functional programming as a different, novel, or exotic way to code”. Even more, though, Scala is apparently “an early example of a new breed of postfunctional languages”.

And that gets us to this blog post.

First of all, Odersky is still missing the point. It’s not about whether you use fold, map, and iter, or whether you can write closures easily. It’s not even really about pure functions vs. side-effects. To code in a functional style is a fundamentally different way of thinking about problems: instead of thinking about problems as nouns that are doing things, functional programming views a problem as a series of transformations to the world which results in an answer. This is why functional programming is considered “a different, novel, or exotic way to code”: it is a different, novel, and (as of yet) exotic way to code. It’s as different, novel, and exotic from OO as OO was from procedural. It’s a different way of thinking about the entire issue. You can check out this snippet of an IRC conversation from #ocaml for more on that.

The paragon of this way of programming is point-free programming, where you are quite literally building up a mega-function that describes how your program works, and then executing that one, single function when you run that program. If your language doesn’t lead people to re-discover point free programming at least in the small, then the language really isn’t taking function manipulation and functional language type conceptions seriously. And that’s the case with Scala: even Odersky admits that in Scala, “currying is more verbose and much less used than in other functional languages”. (Protip to Scala people: If one of the fundamental stunts of a style is pervasive in all the code but yours, you’re not in the same style of programming.)

What really gets me, though, is the claim that Scala is “an early example of a new breed of postfunctional languages”, because aside from the static typing, all the language features that Odersky trots out already exist in Perl. It’s hard to be a vanguard of a new breed of programming languages when there’s prior art from the 1980s.

Don’t believe me? The existence of a book on the topic unconvincing? Then let’s run the list of functional language features from Odersky.

  • Functions as first class values: check.
    sub apply(&$) {  # Take a function as an argument no problem
      $_[0]->($_[1]);
    }
     
    sub times2($) {  # Create a function to take
      print $_[0]*2 . "n";
    }
     
    apply(&times2, 3);
  • Convenient closure syntax: check
    my $x = 2;
    apply { print $_[0]*$x . "n" } 3;
     
    my $times_x = sub($) {
      print $_[0]*$x . "n";
    };
    $times_x->(3);
  • List comprehensions: check. (See perlfunc on list data.)
  • “Curried” function definitions and applications: check-ish.
    Okay, so calling this a “check” on Scala is a bit of a reach (cite, cite, cite, although note thishere is a more sympathetic run-down on Scala currying). Ignoring the foo(2,_:Int) syntax for a moment, we can implement basically the same style of “‘curried’ function definitions” such as Scala’s List#foldLeft.

    sub add {
      my $x = shift;
      return sub { $x + shift };
    }
    add(2)->(3);  # Okay, so you do need an extra ->

    In the case of our apply function above (where we take a function as the first argument), it’s even easier.

    apply { print $_[0]*$x . "n" } 8;

    Now, there isn’t really argument skipping (i.e.: foo(_:Int,3)) as a syntax feature, and there isn’t a built-in curry function, but if you want Scala’s Function.curried in perl, here it is:

    # This code released under Creative Commons 0 and WTFPL.
    sub curry(&@) {
      my($f,@args) = @_; 
      return sub { $f->(@args, @_); };
    }
     
    sub add($$) {
      return $_[0] + $_[1];
    }
     
    my $curried = curry(&add, 2); 
    print $curried->(3) . "n";
  • Lazy evaluation: check. See Scalar::Defer for lazy val equivalents and Tie::LazyList for lazy seq equivalents. People generally use a double-return approach for generators (which I realize are different than lazy seqs and only kinda-sorta lazy).
  • Pattern matching: check (okay, check-ish). See Switch. The decomposition isn’t there, which is the biggest weakness. But the general cumbersomeness and lack of real algebraic data types hamstrings the coolest parts of pattern matching anyway, so I’m calling it a draw. (This should be read as a generous and sympathetic ruling for Scala: Cedric Beust, for instance, rails against pattern matching/case classes and says “it’s hard for me to see case classes as anything but a failure“.)

In addition, perl’s got a few features in its favor for functional programming, like more flexible arguments, autovificiation, list/argument coercion, and dynamic symbol table mangling. Since perl also has OO capabilities, perl is at least as convincing a “post-functional language” as Scala. But there’s even more in common between the two than that.

Odersky’s “post-functional language” is really a subtype of Larry Wall’s “post-modern language”: it’s an attempt to create a language that is a grab-bag of multiple paradigms. And when you do that, you’re just begging for the complaints that you hear leveled against both perl and Scala: it’s too complicated, its syntax is weird, it’s too magical, people write in entirely distinct subsets of the language, etc. (cite, cite, cite) Now, those who master the language (or master their favorite subset of it) love the TIMTOWTDI aspect. But it also means that the language is left as a jack-of-all-trades, master of none. Yes, Scala and perl integrate a lot of powerful tools from functional languages—but learning OCaml still blew my mind, despite knowing perl for years. As I started off saying, Scala is not a functional programming language. It is a statically typed object oriented language with closures.

Now, there is a sense in which Odersky is really onto something. The world of programming is forever transformed with closures and list comprehensions as being mandatory for new high-level languages, even if they’re otherwise object oriented. And software developers are going to need how to work with them effectively if they want to read code moving forward. Yes, after 20+ years, the rest of the programming world finally caught up to one of perl’s fundamental insights.