Hacker News new | past | comments | ask | show | jobs | submit login
Functional thinking: Why functional programming is on the rise (ibm.com)
187 points by Adrock on Jan 29, 2013 | hide | past | favorite | 81 comments



Some ideas that are ubiquitous within functional programming are certainly on the rise, for example:

- functions as first-class entities in programming languages, and consequences like higher-order functions and partial evaluation;

- a common set of basic data structures (set, sequence, dictionary, tree, etc.) and generalised operations for manipulating and combining them (map, filter, reduce, intersection, union, zip, convert a tree to a sequence breadth-first or depth-first, etc.);

- a more declarative programming style, writing specifications rather than instructions;

- a programming style that emphasizes the data flow more than the control flow.

I see these as distinct, though certainly not independent, concepts.

I’m not sure whether functional programming itself is really on the rise, not to the extent of becoming a common approach in the mainstream programming world any time soon. I don’t think we’ve figured out how to cope with effectful systems and the real world having a time dimension very well yet. (I don’t think we’ve figured it out very well in imperative programming yet either, but the weakness is less damaging there because there is an implicit time dimension whether you want it or not.)


Yes, a lot of these are characteristic of functional programming, and many are being adopted. But I think that the idea of using mathematically pure functions---programming without side effects or mutation---is a/the key idea behind functional programming. And it's this purity that divides the communities. You can take high-order functions and folds and put them in just about any language, and you could put OOP concepts like subtype polymorphism into functional languages. But there's a line that neither class of languages can cross over, and that's mutable state.

I know that some developers are beginning to lean in the direction of functional programming by relying on const annotations and adopting a functional style. And I'm very excited and hopeful about the overall trend.


But I think that the idea of using mathematically pure functions---programming without side effects or mutation---is a/the key idea behind functional programming.

Indeed, and it is either a blessing or a curse depending on what kind of software you’re trying to write and the sort of situations you’re trying to model.

For most of the programming work I’ve ever done myself, what I’d really like to use is languages that do have concepts like time and side effects, because they’re very useful, but which only use them in controlled ways and when the programmer actually wants them. I’ve often wondered whether such ideas might be elevated to first class concepts within future programming languages, complete with their own rules and specified interactions, just as today we have variables and types and functions, and a language will prevent errors like calling a function with only two values when it expects three or trying to use the value 20 where a string is expected.

For now, I’m hoping that functional programming, in the pure sense, will raise awareness of the potential benefits of controlling side effects rather than allowing them more-or-less arbitrarily as most imperative languages today do. With a bit of luck, the generation of industrial languages in a few years will then borrow ideas that stand the test of time from today’s research into type/effect systems, software transactional memory, and so on, and perhaps we can have something of the best of both worlds.


What you describe is exactly what Haskell does. You have pure functions by default, but you can have mutable state wherever you want it--it is just constrained to a particular scope by the type system. That is, you can use mutable references, mutable arrays and so on all you want inside a computation, and the compiler will guarantee that none of these references leak outside their scope. Haskell accomplishes this with "state threads" (ST[1]).

[1]: http://hackage.haskell.org/packages/archive/base/4.2.0.1/doc...

Similarly, Haskell has the IO type for containing any side effects at all. This type, as the name implies, can have not only mutable state but also arbitrary I/O--really anything you like.

This has some very nice advantages: for example, you can create your own wrapper around the IO type which only exposes some IO operations. You could use this for ensuring that plugins can't do things like delete files, for example. (This is one of the example use cases for Safe Haskell[2], which is worth reading about.)

[2]: http://www.haskell.org/ghc/docs/7.4.1/html/users_guide/safe-...

You can even reify time explicitly, rather than modelling it implicitly with mutable state. This leads to functional reactive programming (FRP[3]), a new and more declarative way to write things like UIs. FRP replaces event and callback oriented programming, fixing much of the spaghetti code common to most UI frameworks.

[3]: http://stackoverflow.com/questions/1028250/what-is-functiona...

Really, I think "purely functional" is a very unfortunate term for Haskell from a marketing standpoint. "Purely functional" does not mean that we cannot have side-effects, or mutation, or what have you. It just means that side-effects aren't everywhere by default, and don't implicitly permute your otherwise pretty code.


I appreciate the comment, but what I have in mind looks very different to the way monads are used in Haskell today.

For example, I don’t necessarily want pure functions by default in my idealised programming model. To me, a pure function is just a special case of a function whose effects are controlled and where the resources the function might interact with are readily identifiable, for which the sets of possible effects and interacting resources happen to be empty.

Put another way, I don’t see anything wrong, or even inferior or undesirable, with performing a quicksort of an array or some fast matrix computations destructively. However, I’d like my language to make sure I couldn’t accidentally try to use the old data again afterwards (including, for example, in other threads running in parallel). I’d like to be sure that just because my algorithm updates one set of data in-place, it doesn’t also draw a window, block to wait for user input, or kick off a background thread that will reformat my hard drive in half an hour. And in the calling code, I’d like to find out very quickly that just because I created and populated an array over here, and then ran a quicksort that changed it over there, and then printed it out down there, nothing else had any chance to modify it in between.

And I’d like to do all of that using syntax that is at least as clean and readable as today’s best languages, please, not the horrors that often seem to result when functional programming languages try to implement equivalent behaviour with realistic heavily structured/monadic values instead of the neat one-integer counter or append-only log that always seems to be used in the tutorial code samples.

I suspect that to do that will require a language that provides dedicated, specialised tools to support the new programming model. Sure, you could probably do this sort of thing using monads in Haskell, just as you could do OOP in C, text processing in C++, or write in a functional style in Python, but the results are clumsy compared to using the right tool for the job. I’m not sure that tool exists yet for the kind of programming models I’d like to use, but that’s where I’m hoping the lessons of today’s functional languages and academic research will bear fruit over time.


That's very attainable in Haskell and is often well-modeled off the ST monad. You also have a number of "Data types a la carte"-like methods which allows you to build very specific effect contexts in order to precisely guarantee things like the fact that mutable array code never produces events in the UI. These can be achieved by products and compositions of applicative types, free monads, monad transformers, or the "sum of effects" "a la carte" method.

Another big deal that comes out of these more specific effects is that you can have the compiler produce stream fusion to automatically optimize some inner loops, though I don't know how often that actually happens as of today.

(Oh: if you want to play with "Data types a la carte" they're in the IOSpec package, http://hackage.haskell.org/package/IOSpec and are described---somewhat densely---in http://www.staff.science.uu.nl/~swier004/Publications/DataTy...)


You should really take a look at Haskell. What you describe in your 3rd paragraph is precisely the ST monad.

It's true we're still pretty limited in how effects are typed (most effectful stuff still ends up in the "IO sin-bin"), but this is an area of active research and experimentation. This is the way haskell's going, and no one else is even close (afaict).


What you describe in your 3rd paragraph is precisely the ST monad.

Not exactly. The ST monad supports local mutable state, essentially turning a computation that uses state internally into something that looks pure from the outside. I’m looking for something more general where, for example, a function could modify state outside its own scope, but only if it advertised explicitly which stateful resources it would read and/or write, so the language could enforce constraints or issue warnings if various kinds of undesirable and/or non-deterministic behaviour would result.

And really, I want to generalise the concepts of resources and effects on them much more widely. A stateful resource might be a mutable variable, but it could just as well be a file, a database, a single record within a whole database, or anything else I care to model in that way. An effect might be reading or writing part of the state, but it might also be opening or closing a file, or beginning, committing or rolling back a DB transaction. I want a language that can understand the concept that a file must not be read or written before it is opened, or that a database transaction must always be committed or rolled back once it has begun, and warn me if any code paths could permit an invalid order of effects. I don’t just want to throw half my code into the IO monad and hope for the best.

I want a language where I can pass a reference to a large data structure into a parallel map function and get a compile-time error because, somewhere in the function I was applying using the map, there was an attempt to perform a mutating operation on that shared data without sufficient safeguards. But I want to write almost identical code and have the effects automatically co-ordinated because the language understands that concurrent access is possible so synchronisation is necessary, but the spec for the parallel map says that non-determinism is permitted.

And crucially, I want a language where even simple code that should look like this:

    def fib(n):
        if n < 2:
            return n
        x, y = 0, 1
        for i in range(n - 1):
            x, y = y, x + y
        return y
does not wind up looking like this (from [1]):

    fibST :: Integer -> Integer
    fibST n = 
        if n < 2
        then n
        else runST $ do
            x <- newSTRef 0
            y <- newSTRef 1
            fibST' n x y
     
        where fibST' 0 x _ = readSTRef x
              fibST' n x y = do
                  x' <- readSTRef x
                  y' <- readSTRef y
                  writeSTRef x y'
                  writeSTRef y $! x'+y'
                  fibST' (n-1) x y
[1] http://www.haskell.org/haskellwiki/Monad/ST


Your last complaint is not fundamental to the language: it's just a matter of library design. I guess Haskellers don't like state very much in any guise, so having awkward syntax for it is only natural. Both programs are fundamentally ugly, so having it be superficially ugly as well is no big loss.

However, if you really wanted to, you could have almost C-like syntax[1]. The demo in that particular blog post has its own issues, but there is no fundamental reason why you couldn't apply some of those ideas to the normal ST API. I suspect that people simply don't care enough.

[1]: http://augustss.blogspot.co.il/2007/08/programming-in-c-ummm...


Both programs are fundamentally ugly, so having it be superficially ugly as well is no big loss.

Perhaps we’ll just have to amicably disagree on that point. I think making code superficially ugly is a huge barrier to adoption that has held back otherwise good ideas throughout the history of programming.

Many an innovative programming style or technique has languished in obscurity until some new language came along and made the idea special and provided dedicated tools to support it. Then it becomes accessible enough for new programmers to experiment with the idea, and the code becomes readable enough to use the idea in production, and over time it starts to change how we think about programming. We push the envelope, probably developing some ingenious and useful but horrible abuses of the idea along the way, until we figure out how to make those new ideas available in a cleaner and more widely accessible way and the cycle begins again.

I suspect that people simply don't care enough.

Most people are programming in languages that don’t have the problem in the first place, so they don’t need to care.


> I think making code superficially ugly is a huge barrier to adoption that has held back otherwise good ideas throughout the history of programming.

Haskell tries to make elegant code look nice and inelegant code look ugly. When you see something ugly like the example above this is a sign that there would be some more elegant way of writing it. That certainly holds in this case as you don't need an mutation to do the fib sequence.


For something as simple as fibonacci, you wouldn't use the state monad machinery, but go directly:

    fib' :: Integer -> Integer
    fib' n = iterate (\(x,y) -> (y,x+y)) (0,1) !! n
The state monad helps you keep more complicated code composable. But it does have some syntactic overhead, that makes it lose out in simple examples. (Though with a bit of golfing, you could get syntactically closer to the Python example. For example putting the tuple (x,y) into an STRef instead of having two of them, employing Applicative Functor style in some places, and using a loop-combinator from the monad-loops package.)


Concepts like your file state machine can be achieved using indexed monads and dependent types, though that's still fairly black magic. There's no doubt that the IO monad should have more structure, though, and ST is just one way to achieve that. There isn't a globally recognized standard for providing more structure, but there are a lot of fairly common practices (see IOSpec or free monads).

The syntactic convenience is unbeatable, of course. Monads are only first class syntactic notions up to `do` notation. Someone is bound to say "let just implement that in Template Haskell", but nobody really argues that TH macros are the same as lispy ones.


The syntactic convenience is unbeatable, of course.

Exactly.

I’m not in any way criticising all the research and ideas coming out of the functional programming community. Playing with Haskell is driving all sorts of interesting ideas.

I’m just saying I don’t think the mainstream is going to give up a whole bunch of readily accessible and useful programming techniques any time soon, just to gain the benefits of a radically different programming style that sound rather theoretical to Bob the Developer. This is true even if the reality might be that in time Bob’s bug rate would drop dramatically and he would develop new features in a fraction of the time.

I think it’s far more likely that the more accessible and obviously useful parts of that radically different programming style will get picked up over time, and that the underlying general/theoretical foundations will be more useful to the people building the specific/practical tools than to the people using them.

Today, we’ve been discussing how to implement even quite simple effect-related concepts in a functional programming context in terms of (borrowing from a few of your posts in this thread) products and compositions of applicative types, free monads, monad transformers, indexed monads, dependent types, and the problems of uncertain denotation. Poor Bob just wants to get an error message if he forgets to commit his transaction and leaves the DB locked or if he might be dereferencing a null pointer in his network stack. :-)


That's utterly fair. I don't expect Bob the programmer to adopt inconvenient things. I think having static assurances of the like you were asking for will probably never quite be in Bob's purview either, though.

To clarify, I don't think Haskell is the ultimately useful embedding of many of these concepts. I just also don't think there's that much hand holding possible. You start to run up against the limits of inference and decidability in this space. Until Bob the programmer start to meaningfully think about the way to build the effects of his language around different contexts then there's a limit to how many guarantees a compiler is going to be able to make.


What you describe reminds me of Rust's typestate, which they removed. But the "branded types" replacement, combined with the unique pointers, sound promising - see http://pcwalton.github.com/blog/2012/12/26/typestate-is-dead...

I am new to Haskell, but I also have objections to Haskell's notions of purity. For example, accessing your pid or your argv do not have side effects, and certainly do not perform IO, yet these are grouped in the IO monad next to file deletion.


Runtime constant values as IO is a long-standing concern. The existence of withArgs cements the issue (definitely allows for non referentially transparent code to be written with getArgs) but there's more to be said about why withArgs exist and why getArgs is in the IO monad.

http://www.haskell.org/pipermail/haskell/2005-October/016574...

The argument usually seems to play out as "their denotation is uncertain" and therefore they get unceremoniously thrown into the IO monad. I tend to agree with that in that I feel a major point of purity is that it gives you a world sufficiently far from the reality of the RTS to play in.

IO's general status as the "Unsafe Pandora's Box" is a wart in Haskell. I'd much prefer it be called the RTS monad and have something like IOSpec's Teletype type performing the classic IO. It's fixed by convention now though.


IO's general status as the "Unsafe Pandora's Box" is a wart in Haskell.

Isn’t that rather like saying mutable variables are a wart in C? :-)


It's more like saying void pointers are a wart in C. It's appropriate in two ways: for one, void pointers are a wart, and for two, there's no good way to get rid of them without radically changing the language.


Sure. Haskell's wart is automatically verified to be context constrained by the type system, though. There are also lots of tools to mitigate that wart that are also verified.


I agree. Tight, stateful algorithms aren't going to disappear and are harder to reason about (currently) in functional languages. I expect that their implementation and use will shrink over time, in the same way that embedding inline assembler has all but disappeared.

I definitely don't expect, or hope, that monads are the final answer to isolating state manipulations, and I agree with a later comment of yours that the IO monad is not granular enough as it is in Haskell. When a large chunk of code ends up being written in the IO monad or in another monad that wraps IO, you miss out on a lot of safety and reasonability that Haskell is supposed to give you. And I've seen that happen (my own projects included).


"But there's a line that neither class of languages can cross over, and that's mutable state."

I'd add another qualifier for clarity; default or reliable mutable/immutable state. And this really comes up in libraries and such; either the language affords the use of immutability and you can count on libraries being themselves immutable, or the language affords the use of mutation and you can count on the libraries being based on mutation. Immutable languages can "borrow" mutability and mutable languages can "borrow" immutability (const, etc.), but the default matters, and there has to be some sort of default.

(Though while I cast this as a binary, there are some small in-between choices that may be relevant; see Rust, for instance, whose "unique" pointers may be a successful split. If the most useful aspect of immutability is not strictly speaking the inability to mutate values, but instead to guarantee that values can not be mutated by other threads or functions you didn't expect, then what happens if you directly express only that constraint instead of the stronger and more annoying constraint of full immutability? I'm watching that language with interest.)


To me, the future will most likely be languages that allows both functional and OO styles to interoperate. Programmers will pick the style or mix of styles most appropriate to the particular sub-problem they're solving.

We already do this with some of our high-level languages like Ruby and JavaScript. With these, we have higher-order functions, map and friends, closures, etc.. But we also have our familiar OO constructs. Almost every program I write in these languages uses all of the above, not just the functional or OO subset.

I so far have not seen any practical advantage in going purely functional. I've tried it a number of times, but I always find that the real-world programs I write need to be stateful. Yes, functional languages do of course have facilities for handling state, but they always seem super awkward, especially compared to the elegance of state handling in OOP.

For example, consider a simple, 1980s-style arcade game. There are a bunch of entities on screen, each with attributes like velocity, health, etc.. How do you maintain this state in a purely functional language? I've seen various suggestions, but they all seem to boil down to setting up a game loop with tail recursion, and then passing some game state object(s) to this function on each recursion. Doesn't sound so bad, but what happens when you have a bunch of different types of entities? E.g. player characters, monsters, projectiles, pickups, etc..

Well, every time you add a new type of entity (or a new data structure to index existing entities), you could add another parameter to the main game loop. But that gets crazy pretty fast. So then you have the clever idea to maintain one massive game state hash, and just pass that around. But wait, now you've lost something key to functional programming: You can no longer tell exactly what aspects of the game state a function is updating, because it just receives and returns the big game state hash. You don't really know what data your functions depend on our modify. Effectively, it's almost like you're using global variables.

I'm using games as an example here, but the same sorts of problems come up with almost any stateful application.

This is why I prefer languages that allow you to seamlessly mix functional and OO styles. They give you many of the benefits of FP without forcing you to deal with the difficulties described above.


For games and other reactive systems, you should check out functional reactive programming (FRP)[1]. The basic idea is to model time explicitly, working with time-varying values. So you would express your game logic as a network of event streams and signals.

[1]: http://stackoverflow.com/questions/1028250/what-is-functiona...

This is a radically different from the normal imperative approach, and I've found it to be much nicer. Admittedly, I haven't tried making games per se, but I have used it successfully for several other interactive UI programs.

FRP is a good approach for any system where you would normally use events and callbacks. This includes UIs and games as well as things like controllers or even music. So at least for that sort of IO-heavy and stateful domains, there is a very good declarative approach.


FRP is super nice, but no magic. I found that it makes it natural to decompose the codebase in model/view/controller and encourages an explicit state machine for updating the model. At the same time, a time-varying value is a plain old observable. But the discipline enforced by FRP avoids the spagetti trap most event-based systems eventually fall into. No magic, therefore useable my mere mortals :)


Now that is really cool. You've convinced me that this could be a viable and practical approach to handling highly stageful programs in an FP context.

One question though: Does memory/storage become an issue if you're keeping track of values "over time?" If I understand it correctly, you'd have a constantly growing picture of your data as it has evolved, with a complete history of prior values. (Maybe I'm wrong about this part, though.) For applications that are long-running or handle a lot of data, could this be a fatal problem?


You're not necessarily keeping track of all the old values over time. Rather, the core idea is that you program in terms of abstractions that are explicit about time. That is, you write your program in terms of streams of events or signals.

You have signals and events, but you never ask about the value right now; instead, you take these two abstractions and combine them in different ways to get a reactive network. In a way, it's similar to dataflow programming or circuit design: you connect up "wires" into a network that can constantly push through data. Depending on how you write this network, you will need to remember different amounts of past data at runtime.

If you write your event/signal network carefully, you do not need to keep a history of too many prior values at runtime. This is one of the things modern FRP libraries really try to help you with: writing networks that are efficient. At least the ones I've tried are good at this--I haven't had many space problems in my programs so far.

In summary, this is a potential issue, and you may have to be a little careful in how you write your FRP code. However, modern frameworks try to make it easy to avoid these pitfalls, and there is no fundamental reason you can't use memory efficiently with this model.


I'm pretty new to FRP, but I tend to visualize FRP like an Excel spreadsheet where one value change leads to a chain reaction of many values in the spreadsheet.

Would this paint the right picture?


Very well. In fact, one of very first implementations I've ever heard of was done in Lisp and it was described exactly in this way. I think the library is even called "Cells".


For an example of making Pong using FRP, check out this: http://elm-lang.org/blog/games-in-elm/part-0/Making-Pong.htm...

It's not a very long read, and it will help make FRP more concrete with a practical example.


Well, if the game state is so small, then it's quite easy to combine all these functions together in FRP style.

How about big games though? for example, World Of Warcraft or Eve Online. The game states of these are humongous, and the game state's data constructor would be huge.


> Well, every time you add a new type of entity (or a new data structure to index existing entities), you could add another parameter to the main game loop. But that gets crazy pretty fast. So then you have the clever idea to maintain one massive game state hash, and just pass that around. But wait, now you've lost something key to functional programming: You can no longer tell exactly what aspects of the game state a function is updating, because it just receives and returns the big game state hash. You don't really know what data your functions depend on our modify. Effectively, it's almost like you're using global variables.

You have to explain how that works. By "hash", do you mean a finite map (or dict, in Python terms)?

In Haskell you can use a state monad for these game loops. Some game industry insiders (see http://lambda-the-ultimate.org/node/1277) argue explicitly for this style.


A state monad is a decoration of functions that take and return the state. It's certainly prettier, and there are respects in which the parent's complaints are overblown (certainly, it's no worse than imperative languages), but the parent is entirely accurate that a function like

    frobnicateTurboencabulator :: GameState -> GameState
doesn't have a type that tells you anything about what it actually does. Compare that with something like

    on :: (b -> b -> c) -> (a -> b) -> a -> a -> c
where the type tells you basically exactly what the function does.

The state monad doesn't help with this problem:

    frobnicateTurboencabulator :: State GameState ()

Of course, the solution is is some combination of:

1) Split functionality into many typeclasses and hide the State monad, so you can see what functionality is accessed by a function (as mentioned in my other comment),

2) Have functions return a description of updates to the world-state instead of performing those updates themselves (so you know what kinds of things a particular function might do). This might have the benefit of letting you compose actions before applying them, which could in some cases be faster if the updates are likely to be large.

There are likely other options, as well.


> Of course, the solution is is some combination of:

And as always in Haskell: more type trickery. Like lenses, which help with the splitting. Applicative functors might help with "Have functions return a description of updates to the world-state [...]" for free in a sense similar to http://gergo.erdi.hu/blog/2012-12-01-static_analysis_with_ap...


Lenses are awesome, and can help with pulling data out of a WorldState object and updating it thereafter. They do not do a thing about loss of information in the function signature.


You hit the nail on the head with regarding to pure functional style. What I usually find useful it to use OO at high level, macro level, structural level to organize the code, and to use functional style at the lower level to build reusable functions. The lower level basic pure functions form the building blocks that can be reused in different circumstances since they are stateless. The domain specific and state specific aspects are left to OO to abstract and organize.


If you mix FP and OO you'll often end up with terrible FP which simply reproduces the "old" approach: lots of mutable stuff everywhere. Many Clojure toy games are like that: they start with a lot of "variables" in mutable refs.

But it doesn't need to be that bad: you can create a game that is fully deterministic. A game which is purely a function of its inputs. And it can of course be applied to more than games.

The problem is that it feels "weird" to non-FP people.

The state monad is definitely what you're looking for. If you use a state monad approx. 95% of what you just wrote is utter rubbish.

But the state monad (and the maybe monad) sadly aren't that trivial to understand.


> If you mix FP and OO you'll often end up with terrible FP which simply reproduces the "old" approach: lots of mutable stuff everywhere.

What I'm suggesting is that mutable state isn't inherently bad. It's entirely possible that we will someday enter a new age of mainstream, pure FP where we look back at mutable state and cringe. But that's pure speculation. Our current world is full of successful applications written in languages built on mutable state.

So I'm not saying that mutable state is inherently better than the alternatives. Just that the case against it--and for the alternatives--has to be pretty darn compelling to outweigh the tremendous real-world success of languages like Ruby, Python, JavaScript, and so on.


I wouldn't call what you've written a straw-man argument, but neither is it a steel-man...

My biggest takeaway, and an entirely legitimate criticism, is that if all your functions become instead State World (), your type signature no longer gives you much information about what the function does. In light of this I intend, when/if I get around to playing with a game in Haskell (or anything else that involves shipping around a huge wad of state), to look into splitting types of game state changes into multiple typeclasses, so as to see about preserving some more information about what various state transformations touch (both reading and writing)...


The maybe monad has a counterpart from the OO world: the null object pattern. They're not implemented the same way, but they serve the same purpose.


What is your third point if not functional programming?


Functional programming, by definition, is expressing a program as a function to be evaluated. That implies that, at least to some extent, all functional programs are written in a declarative style.

However, we use a declarative style for other kinds of language as well: Prolog, SQL and CSS are three very different examples, none of which is a functional programming language similar to ML or Haskell or Clojure.


I don't think there is one uniform definition of functional programming. It's a vague characteristic of a language in the same sense as "object oriented."


> I don't think there is one uniform definition of functional programming.

Only because people are lazy in their words and thinking.


I agree people never evaluate the function early enough, glad I'm not one.


declarative vs imperative is kind of a subjective thing but functional programming is not the only way to do declarative programming (logic programming and SQL are two examples that come to mind)


I tend to agree. It's a lot like with object-oriented programming: "Hey, this is so awesome! You can encapsulate data, have well-defined interfaces, enforce separation-of-concerns, and, and ..." --> Er, I've always been able to do all that, I just didn't call it OO.

That said, I'm still doing what I can to assimilate those techniques and understand where to apply them.


The thing is that any imperative programmers who have composed SQL subqueries have have been doing this kind of thinking for years whether they realise it or not. The only substantial difference is that the data is in the process' memory as maps and lists as opposed to relational tables in the db. You end up with exactly the same kind of patterns of composition in the code.


This general idea is well illustrated by LINQ: it essentially garbs basic functional programming into SQL's garments and passes it off to C# programmers, who happily use it for a whole bunch of different things. Some of these things (like RX) are really nothing like normal SQL at all.


Completely disagree. Composing SQL queries even on multiple levels (as in subqueries) might involve a way of thinking that remotely resembles to functional programming, it is way too simplistic for comparison with real world functional programs, at least in my experience.

I know I grasped SQL really quickly, and still get puzzled by Haskell after 6 months of trying.


"[SQL] is way too simplistic for comparison with real world functional programs"

Another way of interpreting that is that the ideas behind SQL are so powerful that it's able to be one of the most successful programming languages of all time without all the bells and whistles of a language like haskell.

It's so successful that it can get by with horrid syntax, a ton of special cases built in, and the mess of SQL NULL semantics.

Sometimes it boggles my mind that more functional programmers don't get involved in databases, where all of their ideas are already proven to be useful.

I don't necessarily disagree with you, depending on what you mean by "real world" programs. I just think that if there is already an area where the concepts are useful (whether you call that a "real world program" or not), it makes a lot of sense to keep trying to build from that. Trying to convince someone to learn haskell to build a website when they already know and like ruby is an uphill battle.


"Sometimes it boggles my mind that more functional programmers don't get involved in databases, where all of their ideas are already proven to be useful."

But some do. For example Rich Hickey used Clojure (which both users and encourages FP but still allows to bend the rules when needed) to create Datomic.

It's a DB but it's CRA instead of CRUD. Making it just so much easier to reason about. The DB is ever-growing and any query becomes "query at time t". And later on, when you query again "query at time t", you CANNOT get a different answer.

Typical CRUD DBs are place-oriented mutability mess and, honestly, reading about MySQL fanbois vs PostgreSQL fanbois arguing about which one is the best looks, from a CRA point of view, as a blind man arguing with a one-eyed about who has the best eye vision.

Datomic is ACID, has infinite read scalability and can use SQL DBs (and many others) as their persistence stores.

It is as Real-World as one can get since that Rich Hickey as seen exactly what we're all witnessing daily in the real-IT-world: a gigantic ball of mutability mess.

To me the revolution is on and there's no going back for those who switched.

From there it's just a matter of time.


Thank you. I knew that Datomic existed, and some of the basic things you pointed out here, but I'll take a closer look. It seems like you really think it has a lot of promise.

That being said, I don't think CRA is a panacea. Databases will always have a "read, decide what to do, write" pattern (because that is what happens in the real world, and databases model the real world). If the read happens at time T, and the write happens at time T+100; then you could have a race condition if something happens at time T+50.

Postgres can detect such race conditions by using true serializability (based on a technique called Serializable Snapshot Isolation[1]). It gets tricky to apply the same technique for temporal databases, though I believe it's possible. Do you happen to know what techniques Datomic offers users to help avoid/detect/resolve race conditions?

Don't get me wrong. I think it's a very useful direction to go in. I've done a lot of work on temporal features in postgres. I'm also aware of some of the limitations, however. You still need some kind of coordination and something resembling locks or a conflict detector.

(By the way, please avoid derogatory comments about people who make different technology choices than you do. An argument could be made that postgres is CRA. And even if not, CRA versus CRUD is a small part of what is actually important to users; many of whom face a different set of trade-offs than you do.)

[1] http://drkp.net/papers/ssi-vldb12.pdf


I disagree with both of you. I think you're underestimating what can be done in SQL--recursive queries and correlated subqueries are not part of most competent developers' "standard toolkit"--but I think you're illustrating the problem with the OP's point, which is that most competent developers get through joins and outer joins (usually inheriting a lot of weird mythology like "joins are expensive") and can select/project and that's about where the skills end. So while I disagree with you in principle, in practice most people's SQL skills are inadequate even for an analogy to functional programming.

I would not say that the thought process I use when writing SQL queries is "more like" my thought process when doing functional programming than imperative programming. In truth, the similarity is all in what isn't present: I'm not deeply worried about what the machine is going to do with my request and how it's going to process it. I remain cognizant of what's "really happening" to the extent that I want to avoid obvious performance pitfalls, but it doesn't become the overriding obsession that it is with procedural programming.

With declarative programming I worry much less about whether the result is correct, and this is the primary benefit to me.


Haskell isn't just FP. It has a lot of other stuff, orthogonal stuff---most notably the HM type system---which really helps to take advantage of "pure" FP.

Getting bogged down in Haskell doesn't mean that SQL doesn't have a lot of great compositional aspects that are inherited from its "more functional" nature.


In many ways, SQL is the case that proves how important and practical some functional language ideas are. SQL is, by many measures, one of the most successful programming languages of all time.


And it's probably a matter of ecosystem too. Outside databases you end up depending on stateful libs/components so you're kinda forced to go with the flow, too much inertia.


I think a big one is concurrency.

Highly concurrent application will become more popular. Functional programming via immutable data structures is one sane way to manage that. Clojure is doing it. Erlang has been doing it for years. Haskell has that.

Fear of large, mutable state is well founded.

What else I think is healthy is adoption of these patterns. It is possibly to be diligent and try to apply some of the idea using other languages (C++, Python etc). It is just a different way of thinking and structuring code.


They are assuming that functional programming is on the rise. With the exception of Clojure (which is more popular by virtue of being new), I don't know of any functional language that are in any measurable way more popular (I assume that is what they mean by on the rise) than it has been in the last 10 years.

In fact, the only application I use that is built using functional programming is Xmonad.

Also, none of the top languages on the TIOBE survey are purely functional, although one in the top 20, 'lisp' with .9% and falling, does promote a functional style.

People expound the virtues of functional programming year after year, and then go off and get a bunch done with Python. Steve Yegge said it best: http://steve-yegge.blogspot.com/2010/12/haskell-researchers-...

http://www.tiobe.com/index.php/content/paperinfo/tpci/index....


Hypothetically you are a big company able to deliver increasingly complicated software that far outperforms the competition because of functional programming. Would you want to correct a remark like this by IBM?

Why on earth would you want to educated pointy-haired individuals when you can be another vapid supporter of the six-sigma model?


Why is functional programming on the rise?

I have heard several times that the big payoff with function programming comes from parallel processing. Because functions typically have no side effects they can operate on a set of inputs in parallel without modification. This is important because future increases in processing power are expected to come primarily from more cores rather than higher clock speeds as in the past.

Is this correct? The author seems to focus on other real but lesser benefits.


I've done a bunch of both 'classic' and functional programming, and for me the biggest difference is a switch in code-writing mindset.

In imperative languages, generally, I tell the computer what and how it should do - no matter if it's assembly, C, Java or [most of] Ruby.

In FP languages (Haskell or Scala, haven't worked with Lisps), I generally tell the computer what needs to be computed and expect it to figure out how to do it - what order of execution, what grouping of data, what to cache.

If you compare Java code and Scala code for the same algorithm, using the same JVM API - then the main nonsyntactic difference between them will be a pile of missing Java lines detailing the order of processing steps and loops, which probably weren't essential to the algorithm - when writing the Java code I could've written it in opposite way with the same result.

What I lose in FP is the ability to easily explicitly do time/space tradeoffs. Sometimes I need to control that, and then it's a bit trickier. However, it can be fixed with minor refinement of language and libraries - the original article cites a great example on how memoization should be implemented in all great languages.

Parallelism currently is just a nice bonus - say, I lose 3x performance by not detailing a great execution path manually in C++; but I gain 3x performance since most of the code is trivially parallelizable to run on 4 cores. For example, in Haskell it's often literally a one-line change, while in Java it'd be a pain in the butt to make everything safely threaded.


This is one of the clearest and most concise explanations on the benefits of FP that I have seen. Thanks!


Parallelism currently is just a nice bonus - say, I lose 3x performance by not detailing a great execution path manually in C++; but I gain 3x performance since most of the code is trivially parallelizable to run on 4 cores.

Parallel extensions have been (and are being) added to OOP languages to make it's use not only simpler, but even as a preferred general design.


In order for such extensions to work on most of my code well, my code needs to written in an FP-inspired style that many new additions to OOP languages do - like C++11, python, etc.

As a crude example - there is a big conceptual difference between a for-loop that processes all the elements in a list or array, and a map operation to all the elements in it.

The for-loop specifies that the execution will be sequential and in a specific order, so it can't really be parallelized automagically.

The map-loop says that it might not be such, so you cannot (a) use a mutable state such as counter incrementation inside; and (b) use the 'previous item' in the calculations.

But in practice, you can write most computations in both of these ways - and if you switch from 'idiomatic C' for-loops to map operations (and the equivalents for the many other common data processing tasks), then code is much more parallelizable both in FP and classic OOP languages.

BUT - it means that much of your code needs to be written in FP-style even if the language is not FP, so you need to think in FP-style. If you use these "parallel extensions" and the new "preferred general design of OOP languages" then much of your code will be stateless and w/o sideeffects; much of your code will look quite different than classic/idiomatic code that the OOP langage had earlier.


Thanks for the explanation. Popular "modern" languages like Javascript, Ruby or Python already have many of the "FP" features mentioned in the OP and comments: first class functions (though not so simple Ruby) and high level data processing functions (e.g. map, filter, select).

As best I can tell the big new benefit of FP is the potential, generally not currently realized, for automatic parallelization. The cost is having to think in a new way that is, at least initially, somewhat confusing.

Alternatively non-FP languages could simply import ideas from FP and gain the benefits in an evolutionary way. For example if Mads wanted to he could rewrite the Ruby interpreter to have map, filter and many other methods automatically use multiple cores. Eventually programmers using the new multi-core version would learn which structures were, such as map, or weren't, suc as for loops, going to be parallelized.

There would be many language specific details to work out. For example determining if there are truly no side effects in a particular situation. This is not always so simple in non-FP languages but still not as complex as analyzing every possible for..end loop.

As 4, 8, 16, 32 and more core processors become more and more common the pressure to either change to FP languages, incorporate FP feature in non-FP languages or find some other parallelization methodology (?) will become irresistible.


I heard this too but in my exploration of functional programming I found little to back this up. Automatically deciding whether it's worth running a given function on a different processor or not (i.e. whether the overhead is greater or less than the savings on the wall clock) is not so much different than the halting problem and many implementations either don't try it or don't do it well. Also, every practical functional program needs to deal with the real world, whether it's in a "pure" (Haskell) form or not, and one way or another this introduces ordering constraints that work against parallelization.


I guess I was thinking that the functional language's compiler/interpreter would deal with spreading the work across the cores when appropriate.

For example if a billion item data structure is feed into some function, say a map that reformats a string, it would be sent to as many cores as were available to simultaneously process a portion of the data then recombine the results (kinda like how Hadoop works).

Obviously this is not trivial but certainly seems easier than either doing this automatically in a language with side effects or manually programming the multi-core logic. None of the languages I've uses can do anything like this but I thought Haskell and some of the new generation of languages were headed that way.


Doesn't this just bend back to Moore's law? Sure, there are more "efficient" data structures for use in functional styles now than there were in the past, but they all seem to treat memory as if it is free. Basically, now that we have such impressive computing resources, we can start thinking of the programs we are writing in terms of the abstractions themselves, and less in terms of the abstraction that is the computer. (That is, many of us are lucky enough to not worry about caching strategies, threading concerns, etc.)

The entire debate about immutable structures is amusing when you consider old resources where there is not spare room for a new copy of a string just from a different starting point. (Referring to the new Java behavior of .substring)


I have been meaning to dig deeper into functional programming, specifically Clojure, but as a newbie to functional programming, I am finding it hard to find a detailed tutorial that I can start to get started with the concepts and programming used in Clojure. Would anyone have any recommendations for a guide?


This site is a bit old now (not sure if it's kept up to date) but I found it helpful when I first started playing with Clojure several years ago (wow...that long already)?

http://java.ociweb.com/mark/clojure/article.html


Programming Clojure by Stuart Halloway is the clearest introduction to Clojure I've read: http://www.amazon.com/Programming-Clojure-Stuart-Halloway/


pg's "ANSI Common Lisp" and "On Lisp" are both great. Your question was about Clojure, but the material in those books is easily transferable to other lisp dialects.


Highly recommend LiveScript if you like CoffeeScript or JavaScript or functional programming.

http://livescript.net


LiveScript was the original name for JavaScript in Netscape Navigator 2.0's beta releases.


Any reason why they ripped the original name for Javascript off? I totally thought you were joking until I went to the site and noticed it's a current project.


The name is a joke, the project is not. "LiveScript was one of the original names for JavaScript, so it seemed fitting. It's an inside joke for those who know JavaScript well." (from the site)

LiveScript hasn't been used as a name for JavaScript in almost two decades.


Thanks for explaining.


The majority of people Are Lazy - This is why java and other languages abstracted further than C/C++ became so popular. Functional programming is more natural and comes with a smaller learning curve. It does not require the same amount of discipline to become proficient - nor the conceptual, analytical problem solver skills to master. But that is just the language, what about the design of an large scale application suite?

So people with less analytic abilities and problem solving skills, (I think of those who HAD TO choose Humanities and arts majors here?) Can actually pick it up. This can be looked at as good or bad, in the long run it is probably good overall because the understanding of hardware and memory become less important as processors, memory, storage, and bandwidth become cheaper There will always be the geeks who still understand everything and can design and architect the software for the developers to code.

One downside may be that those with the analytic/problem solving minds will lose their art in a sense and lose the very thing that keeps their minds sharp. Another thing worth mentioning is, there is going to be a lot of changes for developers. Wages will go down as it gets easier to learn how to program - thus more programmers flood the market (supply and demand), also their will be a separation of Architects and code monkeys - the latter being the Humanities graduate type.

To sum up - This will "Dumb Down" your average developer and create a clearly defined separation between developers and designers/architects.


Quite off-topic, but the underscores for the variable names in the first code snippet are totally irritatingly useless and anachronistic in the most ugly looking way.


They mark the private variables so you don't have to remember which ones are private when you read further down the page. That's pretty common place and good style, IMO. What makes you think they're anachronistic?




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: