Thursday, May 21, 2015

First-Class “Statements”

Justin Le (via Andy Matuschak):

One thing I’ve really always appreciated about Haskell is that all “statements” in Haskell (or at least, what would be statements in other languages) are first-class members of the language. That is, (imperative) statements are literally just normal objects (no different from numbers, or lists, or booleans) — they can be saved to variables, passed to functions, transformed using normal functions, copied, etc. Haskell doesn’t have statements — everything is an expression, representing normal data! This really opens up a whole world of possibilities for not only reasoning about your code, but also for new ways to frame ideas in contexts of parallelism, concurrency, exceptions, DSLs, and more.

[…]

In many other languages, sequencing actions is a special part of the syntax — a semicolon, usually. In Haskell, sequencing is not special — it’s just a normal function on normal data structures.

You can even make your own “first class” control flow!

1 Comment RSS · Twitter

Hum. Some people can write C code in any language.

For anyone that's unclear, Le is talking about monads, which are the objects Haskell uses to encapsulate non-functional behaviors like sequential operations, mutable state, and IO so that they don't pollute the rest of the program. This allows the compiler to reason about the functional parts of the program while still allowing the developer to drop down into "unsafe imperative mode" when they have to perform certain tasks that are impractical/impossible to do in a functional way.

The point of functional programming is to describe the relationships between inputs and output, which means that for any given set of inputs the output will always be the same ("referential transparency"). As long as the program is 100% predictable, the compiler can reason about it in all sorts of very powerful ways (correctness, laziness, parallelization), but as soon as you mix imperative logic you go from 100% to 0%. Monads just keep that 0% tightly contained inside sealed objects, so that the rest of the program stays at 100%.

They're a kludge, in other words, and even though I'm not a Haskell person myself I get a distinct whiff of "coder smell" when folks go hog-wild with the things. The more you add non-functional behaviors (which the functional compiler can't reason about), the less benefit you get from coding in a functional language in the first place, up to and beyond the point where you're obviously using the wrong tool for the job and should've just used an imperative language in the first place.

And then, of course, there's the whole Greenspun's Tenth Rule thing, because stuff like creating your own flow control structures would be remotely novel or new to anyone familiar with Lisp. (It's only because of the overbearing dominance C and all its wretched children that programmers lost the ability to think in such flexible ways to begin with.) But that's a much larger issue... :)

Leave a Comment