Functional Programming For The Rest of Us
defmacro.org
defmacro.org
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.
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.
"Functional programming is a practical implementation of Alonzo Church's ideas. Not all lambda calculus ideas transform to practice because lambda calculus was not designed to work under physical limitations. Therefore, like object oriented programming, functional programming is a set of ideas, not a set of strict guidelines. There are many functional programming languages, and most of them do many things very differently. In this article I will explain the most widely used ideas from functional languages"
No where does he say that functional programming is pure programming.
Sure you can do whatever you want, but if the language does not support things like tail call optimization, non-imperative function definition, writing code in functional style turns out to be a lot slower (due to non-tail-optimized function call overhead) and less safe (due to potential side effects in function definition) than if you are writing it in a functional language with explicit support for these facilities.
Various flavours of Lisp have been in the forefront (CMA: among 'popular' languages) in making this functionality available, but I don't know of any (CMA: 'popular') pure flavour of Lisp. (Maybe Clojure --but its preference for 'immutable by default' is quite different from not having mutable values at all!)
In computer science, functional programming is a programming paradigm that treats computation as the evaluation of mathematical functions and avoids state and mutable data.
Sounds exactly what I was thinking - map is not mathematical function - because it can interact with the global state (you can apply map twice to the same data and get different results - for example if in the function you are mapping you use 'time') - and thus using it is not 'functional programming'. If your first-class functions were mathematical functions - then we could agree - but map is not one.
> functional programming is a programming paradigm
NOT a programming language. What I think this means is that your usage of map is such that the computation is what matters, not mutating the state. I can do that just as well in Python, JavaScript, OCaml, Scala, Clojure and Haskell. In other languages too, yes, but not nearly as easily (due to lack of closures/complicated functional types/no first-class functions/...).
If you were to insist that functional programming is just math (no mutable state), then even Haskell and Mathematica are far from functional.
I don't think I quite understand you. I think when you say "mathematical function" you mean "pure function". And when you say "global state" I assume you mean "impure operations".
But (from my understanding) map is purely functional and doesn't do anything impure like IO. Its purely a mathematical mapping between a collection of input values to a collection of output values, based on applying a function to each input value in turn. You seem to be suggesting "map f (map f x)" (that is applying map twice to the same data) is not the same value as "map f x" and therefore its not "mathematical".
It still does not resolve the definition problem - is functional programming programming with pure mathematical functions - or is it using first-class functions (not in mathematical sense)? Which definition is more useful? Which is more widely used?
With that reasoning you could claim addition is impure, because time() + 1 changes over time. map is definitely a pure function. If you apply it to impure arguments, of course the result will be impure. The point in FP is to avoid using 'time', not 'map'.
Let me repeat: you used an introductory sentence as a "definition" of FP and are overinterpreting it. If you read later you will see:
> Functional programming languages, especially purely functional ones...
So Wikipedia distinguishes functional programming and pure functional programming. In fact there is a separate article on pure functional programming, which says that destructive modifications are "excluded", not just "avoided".
Functional programming does not have clear boundaries. You can have advantages of functional programming even if you introduce _a bit_ of FP style in a very imperative program. Conversely, you can write in very imperative style in Haskell.
Defining functional programming as programming with first-class functions is a consistent definition and could be used if not the fact that more people use the other definition (at least that is what the wikipedia definition and other online material makes me believe).
I don't know your background, maybe you are deep in the academic world, but if not, it's likely you are the "rest of us" he is addressing.
http://www.alanmacdougall.com/functional-series/
I'd really like to see these techniques emerge into the spotlight, instead of just being voodoo magic hidden deep in the guts of frameworks.
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.
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.
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?
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. :)
The main difference is the lack of purity, which means that the side effects of a function aren't part of a function's type. It also doesn't have the wide variety of extensions which you can use to do really crazy stuff (like verifiably correct red-black trees, https://github.com/yairchu/red-black-tree/blob/master/RedBla...).
http://news.ycombinator.com/item?id=2622166
http://www.cs.washington.edu/education/courses/cse505/98au/s...
They're roughly equivalent the way Python and Ruby are roughly equivalent, or Common Lisp and Scheme. From any other linguistic paradigm, yeah, they're extremely close. But from one to the other, it feels like there is a tremendous gulf.
A lot of the benefits tmhedberg is talking about come from I/O being a monad in Haskell and the lack of "assignables," which constrains your ability to mix side-effects and state changes with pure code. Of course, you can defeat it if you really try (MVars and unsafePerformIO) but it's not the kind of thing you would do accidentally. And you could achieve a lot of the same benefits in OCaml by writing monadic standard libraries and never using refs.
So, if by "expressive" you mean the type system allows you to express complex relationships, Haskell is more expressive. But if by "expressive" you mean the language allows you to express calculations in more ways, OCaml is more expressive. In my experience, "expressiveness" is usually a foil for some other attribute and doesn't usually illuminate the debate much.
In the end, they're just tools, albeit with overlapping purposes. OCaml is easier to learn and compiles faster, Haskell raises your confidence in the code and has cooler tricks. Both are fascinating and stunningly better than lots of other options. If I had to choose which one to learn today, I'd look at some example code in both and ask myself which one I want to be staring at for the next six months.
I find that in Lisp, for example, I'm able to do partial, tentative refactorings, where I sort-of change something as an experiment, just enough that it works in one example case, but don't completely refactor everything to be consistent with the change yet, because I'm not sure if I really want the change or not. That kind of thing is really hard to push through in languages that care more about static types, and I often find myself thinking something along the lines of: yes I know that function there isn't updated with the new type signature, but I'm only planning to try this out initially with one choice of parameters, and I know that in that case the function isn't even called, so please just run the damn program!
otherfunc = undefined
otherfuncReal :: ...
otherfuncReal = ...
The best exploratory programming I've seen in haskell also does this for types to some extent; you know you're writing music, so you start with something like: data Music -- stubbed in data type with no constructor
Then maybe you decide it involves a series of notes with duration, so you change it: data Music = [(Note, Duration)]
data Note -- stub
type Duration = Inthad to ask, what is more powerful, agda/coq/other?
In practice this means you need manifest type signatures, otherwise the type of a function would be “lol iunno ¯\(°_o)/¯”. Then again, Haskell requires signatures in some cases, such as for Rank-N types, or when you run up against the Dread Monomorphism Restriction. So yeah, Agda and Coq are awesome, but most useful as what they’re designed to be—proof assistants—rather than general-purpose languages.
tl;dr: A constrained system such as Haskell’s, with extensions for aspects of dependent typing, is more practical than actual dependent typing.
http://www.cs.princeton.edu/~dpw/papers/TCS04.pdf
http://www.metaocaml.org/concoqtion/techreport.pdf
http://www.cis.upenn.edu/~sweirich/plmw12/Slides/plmw12-Pier...
slide 8:
summary = impossibleTry Disciple sometime, or Scala!
http://stackoverflow.com/questions/tagged/functional-program...
esp this one (Harrop, Ramsey, Brian are FP heavyweights
http://stackoverflow.com/questions/485418/distinctive-traits...
"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."
“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.
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.
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?
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.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.
function handleSession() {
renderFormPage() // writes response with HTML for form
suspend() // wait for next request in the session
processForm() // process the form data - notice this is the same function
}
It's a very powerful technique and can make web programming very intuitive since you can have a single linear flow for a complex web interaction.Check out Chris Double's tutorial on this:
http://double.co.nz/scheme/modal-web-server.html
Or SISC-Web for a simple but complete implementation:
You're fired.
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.
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.
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.
Off the top of my head, I can rattle off a slew of functionality in Scala that's not in Java:
* Regexp literals
* partial/curried functions
* for comprehension
* argument defaults
* case classes (and switches thereon)
* tuples
* combinators
* XML interpolation
* Mixins
* Fine-grained visibility
Caveat: I'm no Scala expert. Some of this may be in the libraries and not the language proper.
Now... what Java functionality can you name that's not in Scala?
You're right that every bit of complexity Java has also trickles into Scala. For example, Java's broken generics certainly add undesired complexity (type erasure, wonky types) to Scala. Still, I think that idiomatic Scala generally is less complex per unit functionality delivered. It's true that "full Scala" must be more complex than Java because it contains Java as a subset, but I think that more can be accomplished in Scala without making code complex or verbose to the point that it becomes a problem.
In other words, to do comparable things requires far less complexity in Scala than in Java, because Scala delivers the best bang-for-buck by picking the most efficient abstractions. For example, Java concurrency requires a JVM expert to get it right (did you know that doubles and longs aren't thread-safe?) whereas Scala concurrency just requires someone who has a basic understanding of the Actor model.
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.
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.