3 ms·
I've been wondering lately, if we skip performance as a consideration (for example lazy evaluation), what is the difference between functional programming and i
by zackmorris 12y ago
I've been wondering lately, if we skip performance as a consideration (for example lazy evaluation), what is the difference between functional programming and imperative programming without globals, pointers, mutable variables or shared memory? In other words, would an imperative language without side effects (that could do static code analysis) be any different in practice than FP?
I'm very serious about this, because as far as I can tell, the next best aspect of FP might be first class functions, but those are starting to be used more in mainstream languages (at least the technique of applying transformations on generic data rather than writing special classes everywhere or using templates).
I'm beginning to feel that the real advantages of FP are being obfuscated by unusual syntax. There should be no reason why we can't go from some of the FP notations to the plain old algebra style (x=y) of C-style languages like Javascript. With better references and immutable variables, we should be able to split calculations up over several lines and have the compiler figure out how to optimize it into basically FP code.
P.S. I do know lisp, so I'm asking for a rather more enlightened answer than just to research it further.
- dustingetz 12y agoIt's different in practice because languages have built-in "opinions" (often codified by syntax, or the standard library, or other ways) that heavily influence their ecosystem. Functional javascript, or python, is not awesome because the default datastructures are mutable, and the ecosystem of libraries are written in an OOP style using mutable data structures. There is some small value in writing the code you control in as FP a way as possible, but you aren't going to have a ton of success in that unless you are willing to rewrite your dependencies to also be more functional. ReactJS may be a killer app that can influence javascript's "opinions" at the ecosystem scale, but that is going to take more time. I've been using ReactJS since it came out as tech lead on small teams, and it was not without challenges to get an OOP trained team to use React well, and to avoid the OO parts of React. Edit: In theory, yes, if you could somehow statically enforce that your C code (and dependencies, including the OS) have no side effects, then some hypothetical compiler could combine your imperative C statements into functional expressions, though I don't know what advantage that would give you. Maybe I have misunderstood your post.
- tel 12y agoPure FP is very different from imperative languages because it has no notion of temporal order. You can (in truly pure FP) evaluate things in whatever order you choose and stop as soon as you're satisfied. The language cannot care at all [0]. That said, FP often involves the introduction of monads which restore sequencing (along with many other beneficial effects). A monadic FP computation is very similar to a plain imperative computation... just with all of the arbitrary details automatically selected to be coherent and optimal. You can even pretty easily embed OO in FP languages (though it gets a little hairy sometimes) since as soon as you can simulate open recursion somehow you can get late-binding as you like. See Oleg's O'Haskell papers for this kind of nonsense. [0] In this regard, even Haskell is impure since it allows for non-terminating computation which can be seen as an impurity since you cannot expect to just evaluate `let x = x in x` repeatedly and get anywhere meaningful. Other languages like Coq, Agda, Idris are terminating (thus not Turing Complete) and therefore truly pure.
- zackmorris 12y agoThank you, I hadn't considered that FP can evaluate in arbitrary order or simultaneously. That makes sense, because if there are no dependencies between code paths (so no side effects) then there's no reason they can't be executed at the same time. They didn't mention that back in the Scheme course I took in college, and I think something vitally important was lost on us (although in fairness they did emphasize that the code was evaluated, not run sequentially). Seeing how monads reintroduce temporal dependence is also an astounding insight, and I can't believe that I've never seen them described that way. That means that the monad has more in common with, say, the mutex, than it does with I/O. I've always tried to approach them with metaphors like sockets and utterly failed to grok anything for more than a couple of days. I'm thinking that if Haskell is an "impure" functional language, then I would like to see a "pure" imperative language. I envision it as similar to Go but multithreaded and basically every function in the language would be its own process, communicating with sockets (so basically a shell with C-style syntax). The overhead could be largely eliminated with a stackless context switcher. It wouldn't be able to achieve the optimization of FP but it might be more approachable to the mainstream and by extension maybe iterate faster and lead to higher productivity. I’d like to see it take the place of OpenCL/CUDA and SIMD because I find them tedious compared to more elegant languages like MATLAB/Octave.
- Tyr42 12y agoConsider one particular case, where we need to read in a gig of data (made of many records), filter out some records, compute some stream of transformed versions of those records, and then write out the rolling average. This actually sounds pretty nice to write as a shell pipeline (and that's a really good way to do it), but really, it's likely that you'd end up writing some code like main() { q = queue(5); avg = 0; while(!eof) { r, eof = get_record(); t = transform(r); if(q.size() >= 5){ avg -= q.pop(); } avg += t; q.push(t); print avg/q.size(); } } or something, but it'd actually be annoying to extract out the logic for handling the rolling average and split it out from the looping code, at least if you want to maintain constant memory use, and if you had to do something similar in a few places, you'd end up duplicating code. I claim that it's possible to factor that code nicely out in Haskell, and still get the compiler to generate the same machine code as the C loop. This doesn't particularly use first class functions, and more relies on the combo of sufficiently smart compiler and sufficiently strong guarantees about what code will do. I also take slight offense at calling C-style languages "plain old algebraic style", since it'd be really strange in algebra to say both x=5 and x=6. I would not hesitate to call FP languages where you can substitute equals for equals and such the algebraic languages.
- Dewie 12y ago> I'm beginning to feel that the real advantages of FP are being obfuscated by unusual syntax. Or that unusual syntax is precisely motivated by trying to seamlessly and naturally express FP code. Either that or they were just being intentionally obtuse... come on, man. Which sounds more likely of these two? I'd personally never want to program in a language with the semantics of Haskell, and the syntax of a C-like language. > With better references and immutable variables, we should be able to split calculations up over several lines and have the compiler figure out how to optimize it into basically FP code. Or just dive the code up into whatever temporary and intermediate steps that you need with let-in expressions and where-declarations? I mean, why not? If what you want the compiler to process is FP code, then just divide it up like you would divide up FP code. FP /= one liners.