Hacker News new | ask | show | jobs
by creativeCak3 1615 days ago
Forgive me if this sounds ignorant, but who is using pure-functional approaches in industry?

Again, please correct me if I'm wrong since I've been industry for barely 2 years: back in school functional programming looked cool, but when I entered industry(and even in my exploration through personal/OSS projects), I have found it to be nothing more for the most part than a cool toy to play with. I can somewhat see the benefit when it comes to parallelizing Big Data, but that seems to be a very special case.

Again if I'm just being ignorant, please educate me :)

5 comments

Lots of people take useful parts of the functional paradigm without bringing in the whole shebang. Javascript being at the top of the list of languages in that page is a good hint at how people use it: things like Array.map are often used instead of procedural counterparts because people consider the pipeline-like data flow to be easier to understand than ad-hoc for loops, to give one simple example.

Promises and the async/await syntax sugar on top of them are another JS construct that borrow quite a bit from functional literature.

I see what you mean...Even I myself have written code along the lines of "array.map.filter.this.filter". And indeed it can be more readable certain times. But I guess what I was referring to is that sometimes it seems that people are "preaching" functional programming as gospel. But I could be misinterpreting things.
I mean, you can go all the way to the deep end, but like any tool, there are good reasons to be pragmatic, and avoid just using a tool for its own sake. Sure, you can get lost in fantasy land[0] algebras if you really want to, but generally I see it as a pyramid of usage (i.e. a small number of people that care about the mathematics, a slightly larger group of library authors that use fantasy land and friends to inform API design decisions, and a larger portion of library consumers that benefit from the academic roots of those design decisions.)

[0] https://github.com/fantasyland/fantasy-land

My software team uses Haskell to help build tooling and support around an enterprise ISP environment. It's a shift in thinking from standard imperative/OOP programming, however, what we've gained is confidence in maintaining and refactoring systems that constantly change due to business reasons over the period of years.

Purity helps quite a bit with narrowing down bugs; you simply check that your inputs and outputs are correct without having to ever worry about state. We use effects to narrow the types of functions that can be legally called inside specific domain logic, which also narrows down a large class of bugs that we've seen creep into other code bases.

However, it's not a magic bullet. Time to getting someone unfamiliar with Haskell up to speed can be costly. Discovering time-saving idioms in a sea of bad documentation is frustrating. Smaller ecosystem than other popular languages means less blogs, and in Haskell's particular case the information seems either too low or high level with no in between.

Still, with 250k of production lines running as stable as can be, we have no complaints.

Pure-functional techniques can give advantages 'down the road', regardless of what language they're used in. For example, pure functions can be tested without any mocking; they can trivially be made concurrent/parallel; their contents can be rearranged/refactored (referential transparency); etc.

Unfortunately it's very tempting to intorduce side-effects 'just this once', which can make those techniques less useful, and takes some discipline to avoid. For example, in Scala it's easier to just throw an exception instead of wrapping results in a 'Try' type; or likewise for null/'Option'; etc. mostly since those results then require map/mapN/flatMap/traverse/etc. to handle, rather than giving us values directly.

However, I think it's usually worth the effort. For example, those map/mapN/flatMap/traverse functions are essentially 'setting policies' for how effects should interact; whilst the 'core logic' can remain completely agnostic.

As a very simple example, if we have 'l: List[A]' and 'f: A => Option[B]', we can combine these in multiple ways, e.g.

    l.map(f)     : List[Option[B]]  // Run f on all elements, keeping all results
    l.flatMap(f) : List[B]          // Run f on all elements, discarding empty results
    l.traverse(f): Option[List[B]]  // Run f on elements in sequence; abort if any are empty
We can replace 'Option' with 'Future' to talk about concurrency rather than emptiness. We can replace 'Option' with 'Try' to talk about exceptions rather than emptiness. All of those expressions remain identical.

More esoterically, we can replace 'Option[T]' with 'Reader[X, T]' for dependency injection of an 'X'; etc.

I've used these techniques commercially in PHP, Python, Javascript, Haskell and Scala (and academically in Racket, StandardML, Coq, Idris, and Agda too)

I used to work at IOHK which built the Cardano blockchain in Haskell (and even a bit of Agda in there too). It's cool to work with, features like liquid haskell have ruined most languages for me, but it's a real PITA when it comes to 'normal' things like building a CRUD app. At least it was for me. Also the build times can get horrific.
My company is all-in on Haskell. We write a web application for the reinsurance industry. It's working great for us.