The standard technique for making mutable programs immutable is to write a “verb” instead of a noun. For instance, instead of spending time trying to describe the state of the pac-man board one should instead describe the exact ways that it changes. Once you’ve modeled this, any sequence of changes (potential, actual, what-have-you) is an immutable record of a pac-man game. The notion of “mutation” only arises as you “fold” over such a sequence of changes.
Monads, types, currying… they’re useful, but, in a way, dodges.
They’re not really dodges. They’re the basic building blocks available once you’ve taken this perspective (or really, were always there but are now emphasized). To ask how to program any old mutable program without encountering them is possible, but you will gain fluency and power by knowing the ground rules by heart.
Like any game, one doesn’t need perfect fundamentals to play—but professionals spend their time there.
Yes, all those professional functional programmers…I guess us functional JS developers will just have to get paid as hobbyists. ;)
I think that FP has an image problem, caused in no small part by the overly academic nature of a lot of the monad, type system, and other work that’s done and which obscures (both in the practice and the preaching) the core awesome of FP:
To me, those four things (and you could aggressively reduce with better verbage them down to one or two) are what constitute >90% of functional programming, as it applies to solving problems. Type systems are an implementation detail. Lazy evaluation is an implementation detail. GC is an implementation detail. Monads, if I could be bothered to cut through the really obtuse explanations that litter the internet, I suspect will reduce to an implementation detail. Immutability (as realized through read-only references or copy-on-write or whatever else) becomes an implementation detail.
And this reductionism is kinda great, right, because it lets you say “Aha, my language doesn’t support x/y/z, but what can I do to get it into a point where it can be used functionally?” And then, you can write functional code in JS! Or C! Or Ruby! And then everyone can learn how to adapt this great style to their existing environments instead of lumping it in with the weird ravings of PL wonks and assuming that it’ll never to anything for them and then missing out on map/filter/reduce and immutability and easy concurrency and all the other wins.
I’d appreciate Irene or any of the other vocal FP users we have here to correct my position, of course–I’m not as skilled on the finer points.
I would happily characterize what you describe as “fundamentals” just the same. These ideas are core and familiarity breeds comfort with the sort of “stateless” programming methodology I described.
I like your four things. I think they cover a good portion of interesting revelations of the “functional” culture.
I disagree that type systems are an implementation detail as they are important in capturing and describing the meaning of programs outside of their computational semantics (which are obviously important but only one interpretation, moreover one not emphasize by points 1-4).
I agree that laziness is an implemenation detail, but it’s very close to a much more fundamental thing that’s somewhat absent from 1-4: the distinction between values and computation. This is well explored in Call-by-Push-Value and somewhat in the dependently typed languages. This is also a more interesting place to talk about immutability which is, as spoken, an implementation detail but connects much more closely with the notions of what a “value” is.
Finally, monads are certainly not an implementation detail but instead a fundamental “gem” discovered when playing in the space outlined in 1-4 which I really suggest people learn about. You can obviously do without this familiarity, but it’ll you gather it you will gain such a wonderful tool of mental organization that you will wonder how you survived without it.
But let’s be clear: FP is not a “technical” quality but instead a cultural one. You can write functional C or Fortran and many of the best programmers have. You can use mutability you can deal with memory management. All of these things are available and embraced by “FP”. You just can’t do it without being explicit. That really changes the game.
Also, to be totally clear, I’m in total support for functional JS—or in any language! I don’t think the technology has much to do with anything besides the pain tolerance you’ll need.
And if you want an exercise in pain tolerance, I’d love to see where someone could take this experiment: https://github.com/tel/js-algebraic/
This started as an interesting article but it seemed to leave-off just when I expected the good part to begin.
What are the techniques that would allow someone to easily implement a functional version of Pacman or Asteroids?
The best I could find was this (and parts 2, 3, 4, follow-up).
I fully agree! I glanced over the archives, but there was nothing that seemed like a Part 2. I guess the meat of the post was the assertion that removing mutability allows one to reason better about programs, but I think most of us have already heard that assertion.
I wonder if some one could point us to a easily readable exposition of WHY FP makes reasoning about programs easier. Thanks!
Um, this ended a little abruptly, I thought. Is there a follow up post? I looked in the archives, but could not decide.