10 ms·
Functional Programming For The Rest of Us
- sreyemhtes 15y agoThis is a much clearer explanation of the benefits than most of the other attempts I have seen.
- adamc 15y agoI was disappointed because I was hoping it was a new piece -- in general, I have found coffeemug's writing well worth my time.
- eof 15y agoAside: I am maybe 50-60 hours into my first haskell project using yesod. I have read about half of "real world haskell" and about half of "learn you a haskell". Other than this, all of my experience is in iterative languages. (c++,python,php). One thing that comes up is "if your program compiles it's almost certain to be correct"; and it has been true again and again for me. It's an odd, eery feeling that honestly I haven't quite groked how it is happening that way. I don't understand completley what I am doing, a combination of not thinking like a FPer, not knowing the idioms of Yesod, and not being entirely familiar with the syntax of Haskell; so I am sometimes stuck on "how" to get the type that I need. So I will sometimes try a couple things almost randomly; then it will compile and it basically is always doing what I want it to do.
- eru 15y agoIf you add some QuickCheck specifications, the programming by brownian motion ("try a couple things almost randomly") will work even better.
- chousuke 15y agoI think the "if it compiles, it works" has to do with Haskell's type system being much more expressive than most static languages, and that most of your code will be declarative and pure. Purity helps because your program will necessarily be composed of small, self-contained modules (usually functions) that have no implicit dependencies. The type system helps because you can encode a lot of the code's intent in type signatures, which prevents code that does not match that intent from compiling. Monads are a good example. Whenever there is some special execution requirement (eg. ordering for IO) for operations, you may be able to express the requirement as a monad, and then any operation outside that monad can't accidentally mix with it. In addition, because monads allow you to enforce how operations are composed, there is no way for the programmer to forget to adapt the output from operation 1 so that it works as an input for operation 2. That's abstracted by "bind". I'm a Haskell newbie myself, but there are a lot of mind-bending tidbits around the Internet in how to encode intent in various ways using the type system... It's not the most powerful system imaginable for that purpose, but as far as practical languages go, it's probably at the top.
- tmhedberg 15y agoAgreed; after getting used to working with Haskell's type system, I've found it kind of painful to use languages with weaker, less expressive type systems (which unfortunately, is basically every practical language other than Haskell). The ability to transform all manner of bugs into compile-time errors via the typechecker is indispensable. Once you start digging into GHC extensions like GADTs and type families, it gets even better. I never feel nearly as confident about the correctness of code I write in, say, Python, even when using a full test suite.
- beagle3 15y ago> which unfortunately, is basically every practical language other than Haskell Is this also true of Ocaml? I have experience in neither, but my understanding from reading up on this says Ocaml and Haskell are roughly equivalent, and if anything - Ocaml is even more expressive. Anyone with real world experience who can comment on this?
- tmhedberg 15y agoI can't answer you with any real authority, since I haven't used OCaml. But from what I understand, it lacks type classes, which are absolutely central to the richness of Haskell's type system. Whether or not it makes up for this in other ways, I can't say. OCaml is also strict by default, with optional laziness, whereas Haskell is the opposite. This could be seen as either an advantage or a disadvantage, but either way, it is a very fundamental difference. If you are considering learning one or the other, I'd advocate for Haskell purely on the basis of it being the closest to mainstream of all the static functional languages. There is a huge variety of libraries available on Hackage, and the community is very active, welcoming, and friendly. Haskell (GHC in particular) is also the laboratory in which the majority of interesting FP research is currently being done, if you care about that at all. Or just learn both languages, so you can compare the benefits and disadvantages for yourself. :)
- njs12345 15y ago
- anthony_d 15y agoI'm in pretty much the same boat. I feel kinda dirty playing with the type signatures to see what compiles, but if it compiles in Haskell it probably works.
- bryogenic 15y ago/me adds this article to my pile of articles to read
- bazzargh 15y agoNice article, but its a bit irksome that the MessageHandler example drops the conditional and doesn't replace it - the code at the end of that section isn't equivalent to what he started with.
- rauljara 15y agoKudos to the piece for being well written, readable, and clear. But I'm worried about a "for the rest of us" that starts off with first Plato and then lambda calculus. The problem with "the rest of us" is that these concepts aren't inherently neat. Disclaimer: I'm not one of "rest of us". I'm learning Haskell, just because I enjoy having to think in a new way. A lot of FP explanations start off with immutability. After plato and lambda calc, that's where this one goes, too. I think because it's a relatively simple concept, and kind of mind blowing that you could do something useful without incrementing i in a for loop. And then the follow up example is normally how you can replicate a for loop in functional programming. Which is again neat. But if you aren't into neat things for their own sakes, you've got to ask why? Why replicate a for loop when you could just use one? (answer: you don't really replicate for loops in FP) They aren't asking why, in the sense that they're curious. They're asking why in the sense of "Why would anyone do that? That's stupid." If you aren't into having your mind blown for no apparent reason (some aren't) the only really compelling thing about the first several pages of the piece is the "Benefits of FP". That's the motivation to learn these crazy new concepts. It should really come first. I think it should come first in any discussion of FP for people who aren't familiar with it. Because for most people to learn, they need a motivation. Your programs will be faster because you can do concurrency super easy is pretty good motivation. Sadly, "because it's neat," is generally not.
- tomp 15y agoThis article is another one of those that confuses functional programming with pure programming (which is, I believe, by definition also functional). You can do a lot of functional programming in a language where values are mutable. I use it all the time in python: the map and filter functions, list comprehensions, zip, ... For me, functional programming means having first-class functions that can be passed to/from other functions. A standard library of common functional combinators help, but you can always write your own. Funny, but some of the most often mentioned functional languages, such as OCaml and Scala, allow liberal use of mutable variables. They just make it a bit harder/more explicit, so the programmer has to give more consideration into it.
- 15y ago
- dustingetz 15y agoi wrote this article off about when it makes incorrect comparisons between immutable values and final variables. someone who read it, is the rest of the article worth reading, or even accurate? there's certainly a need for articles like this, targetting an audience of java devs, if only they were correct. I haven't found much.
- spacemanaki 15y agoYes, it's worth reading and it's basically accurate, although I'm not sure the accuracy is really as important as the general big picture, since there aren't that many examples. Is there something specific that you can point out where the article is actually incorrect? There are only a few paragraphs in the beginning that mention final variables (and those only use Java primitives). I agree that there's a distinction to be made but I don't know how useful that would be in this kind of article. If you're going to be splitting hairs over immutable values and final variables, you're probably not the target audience. On the other hand, Java devs who can't be bothered to finish a 20 page article probably aren't either. FWIW, I think that Rich Hickey's Clojure videos and some of his more general talks on state, time and identity are probably some of the best "intros to FP for Java devs" out there.
- calpaterson 15y agoTo be fair the the grandparent, the difference between immutable data structures and final variables in imperative languages is large and fundamental. If the author is (and I don't know, because I haven't read the article recently) making this analogy then it is going to be extremely confusing for some people.
- spacemanaki 15y agoThe article doesn't make this analogy, that was my point. It doesn't really delve into immutable data structures at all, and just discusses FP in broad strokes. This isn't really a bad thing, since I don't think it was meant to be a deeply technical article.
- fahad-sheikh 15y agoI found this article very useful, and helpful in de-mystifying the world of functional programming. Are there other articles that cover functional programming theory in plain words like this?
- gtani 15y agoGlad you asked! I did this in about 7 minutes, but I could spend a week talking about how lispers, ML, clojure scala and haskell approach this. http://www.reddit.com/r/haskell/comments/qxmh3/what_are_some_good_and_short_max_3_pages_articles/ http://www.reddit.com/r/haskell/comments/qxmh3/what_are_some... http://stackoverflow.com/questions/tagged/functional-programming?sort=votes&pagesize=15 http://stackoverflow.com/questions/tagged/functional-program... esp this one (Harrop, Ramsey, Brian are FP heavyweights http://stackoverflow.com/questions/485418/distinctive-traits-of-the-functional-languages http://stackoverflow.com/questions/485418/distinctive-traits...
- bmj 15y agoI'll add an additional question to this one: are there any good sources of small, "real world" app examples available? I realize I could look at, say, the HN codebase, but I'm curious if there are smaller examples available, too.
- AdrianRossouw 15y agosuch a wonderful article , sullied by java based examples.
- evincarofautumn 15y agoA great read. Just a couple of things that jumped out at me: “In functional languages automatic analysis of functions and finding good candidates for concurrent execution is as trivial as automatic inlining!” It isn’t exactly trivial. If you can evaluate anything concurrently, then you still have to figure out what’s worth the overhead of spinning up a thread to run concurrently. And many operations are inherently sequential even if they aren’t imperative or side-effectful—parsing, for example. Still, the gist is that concurrency is easiest in a pure language and a functional style, and I have no bones to pick with that. “…infinite data structures, something that's much more complicated in a strict language.” Infinite structures are still pretty easy to construct in strict languages. For example, you can use ranges of the sort in D’s std.range library, as described in Alexandrescu’s “Iterators Must Go!” talk.
- fusiongyro 15y agoOf course benchmarking is essential, but the Control.Parallel library can decouple expressions to run in parallel (called sparks) from threads, and manages the whole shebang for you. You more-or-less say x `pseq` y and it will try to evaluate them in separate threads if possible. The RTS statistics will tell you how many sparks got "converted" to run on another CPU and whatnot, so you can compare and see if you actually got an improvement, but it is a bit easier than spinning up dedicated threads, assuming you're parallelizing pure computations. For true concurrency, you still need to deal with threads.
- jiggy2011 15y agoGood article , cleared a few things up for me. One thing I am still a bit hazy on though. He mentions that continuations could be used in the context of a web app to maintain state between HTTP requests. I'm not quite clear how this would actually work. Lets say you have something like this (in psuedocode): Let's say we have a counter we want to increment on each request. doHTTPRequest(requestVars) { renderPage(requestVars) pause() return requestVars + 1 } doHTTPRequest(doHTTPRequest) Is that approximately how this works? In which case, how would it work for doing more than 2 requests in a row?
- Periodic 15y agoNode.js is built around a lot of continuations, if I recall. It's very common in event driven computing. I believe the basic way to do it is that the function that processes the original request both returns the output and the continuation, then the next time the user connects it would use the continuation instead of the original function. function doHTTPRequest(requestVars, renderPage) { (content, renderNextPage) = renderPage(requestVars); return (content, function (newRequestVars) { renderNextPage(newRequestVars); }); } It's a little awkward, and maybe not the best example of CPS. But basically what happens is the request gets handled and returns the output and something to do next. Then you return your output and some additional computation that will get executed later, in this case a function that renders a different page. This is computation that hasn't been evaluated, but which can be passed around to evaluate later. Note that this whole function could be replaced by renderPage, but I wanted to make things more explicit. A good language would let you write doHTTPRequest = renderPage; Also, when your config would probably specify that it should call renderPage and so that function would get passed around or held by your controller/dispatcher until the actual doHTTPRequest is called.
- jiggy2011 15y agoThankyou, that has made it at least slightly more clear to me I think :) So what you need basically in the core of your server is some data structure (possibly keyed by the client's IP address and TCP port number?) that contains a bunch of functions with prepopulated arguments (curried functions?). The prepopulated arguments are basically the state set by the previous request. When a new request comes in you somehow match it up with your data structure and execute? I guess the continuation part is to force the I/O to happen at the right point, i.e make the next request depend on the execution of the first? Of course Javascript is not really functional so that needn't be explicit.
- agentgt 15y agoIs it me or that "A Walk in the Park" sounds like Sheldon Cooper from the Big Bang theory: "Fire up the time machine. Our walk in the park took place more than two thousand years ago, on a beautiful sunny day of a long forgotten spring in 380 B.C. Outside the city walls of Athens, under the pleasant shade of olive trees Plato was walking towards the Academy with a beautiful slave boy. The weather was lovely, the dinner was filling, and the conversation turned to philosophy." Big Bang: http://www.youtube.com/watch?v=lDxv9hSKdY4 http://www.youtube.com/watch?v=lDxv9hSKdY4
- Groxx 15y agoOther way around, I believe. The date on this article is 2006, BBT started late 2007.
- brooksbp 15y ago> Programmers are procrastinators. Get in, get some coffee, check the mailbox, read the RSS feeds, read the news, check out latest articles on techie websites, browse through political discussions on the designated sections of the programming forums. Rinse and repeat to make sure nothing is missed. Go to lunch. Come back, stare at the IDE for a few minutes. Check the mailbox. Get some coffee. Before you know it, the day is over. You're fired.
- veb 15y agoSo you'd rather have some dinosaur sitting at a computer? Someone who doesn't care about programming, doesn't care about the latest or newest ways to do things? Doesn't care about improving themselves? I must admit, I'm like this _sometimes_. But that's only because I'm using PHP :) If you have a problem with your developers doing this, you're doing something wrong.
- squires 15y agoInteresting, well written article. However I was surprised to be made aware of the existence of a logician named Haskell Curry. The name struck me as the punchline to a joke only told and appreciated by the uber-nerds in the halls of elite university mathematics departments.
- yathern 15y agoAnyone who liked this read might also like the read "Gödel, Escher, Bach: An Eternal Golden Braid". Its such an interesting book, and teaches through very simple ways.
- deleted 15y ago[deleted]
- michaelochurch 15y agoAfter racking my brain for years trying to figure out why shitty "design patterns" have been winning while functional programming (despite its superiority to typical object-obfuscated architecture) remains on the back-burner, I've come to a few conclusions. 1. The name "functional programming" doesn't sell us; it just sounds impractical. What we do isn't really "functional programming" in a purist sense. We need side effects all the time. We just have an understanding of the need to manage state (not eliminate it) properly. We need a better term for the hybrid functional-preferred/imperative-when-appropriate/very-occasionally-OO style that good engineers use, but all I can come up with (for how we "functional" programmers do things as opposed to the enterprise hoipolloi) is "non-shitty programming" and that sounds biased. 2. Usually, when we showcase FP, it looks like we're hawking complexity. We get into tail recursion and abstract data types right away. In fact, proper use of FP reduces complexity a great deal. For example, Scala is actually less complex than Java by far. On the other hand, it's hard to present Scala to a Java programmer without it appearing that one is trying to shove more complexity into his workflow, because it's only after a few months of learning how FP works (and that you don't need classes to program, you just need functions, because that's what algorithms actually are) that people realize how much simpler code becomes when done properly, and that functional programming (unlike <managerially-empowered flavor-of-the-month X> in Java) does provide life-long, substantial boosts in productivity and product quality. Until people get to that point, they'll feel like we're just shoving a tough learning curve on them.
- lemming 15y agoScala is actually less complex than Java by far. I'm sorry, but I can't let this one go by. I can accept the argument that FP may be less complex once you get used to it (not sure I agree but let's go with it) and immutability by default is great but just because Scala and/or it's surrounding community allow or encourage this style doesn't mean that Scala-the-language is less complex than Java-the-language. That's a statement bordering on the absurd - I would say that Scala is demonstrably massively more complex than Java. Many of the things that make Scala great are extremely complicated, both theoretically and practically. That doesn't stop it being great but it does make it complex.
- zvrba 15y agoFunctional programming for the rest of us: please structure your code, to the extent that it is possible and practical, around functions whose return value depends only on its arguments.
- fabjan 15y agoJust a nitpick: Erlang is not an academic language, it's designed in the industry, for industrial use.