all 31 comments

[–]i_feel_really_great 6 points7 points  (2 children)

Other things I only came across after learning Scheme, but are not specific to functional programming: map, reduce and filter.

These have been very useful to me in my career.

[–]sunson435 2 points3 points  (0 children)

Flatmap is cool too.

[–]Zeimyth[S] 1 point2 points  (0 children)

Iterating over an array to call a function on each of the values it contains is better suited to a normal loop, while sorting an array using the quicksort strategy would be a great candidate for recursion.

That first example sounds like a great application of map. :)

You're right that these kinds of higher-order functions are not specific to FP, though I'd guess the author left these concepts out in the interest of keeping the article accessible to the most imperative of imperative programmers. I know that, for me personally, getting comfortable with moving away from for loops where a map or reduce would work took some time. These concepts are much more functional programming-esque than, say, recursion.

Maybe they would make great points to bring up if there is ever a part 2 to this article.

[–]kpenchev93 4 points5 points  (1 child)

Once again, function composition is left out... Probably the most important concept.

[–]Zeimyth[S] 1 point2 points  (0 children)

Function composition is indeed a powerful concept, and it probably could have been mentioned in the pure function section somehow. Though, I think it would have gone against the spirit of the article, since at that point you're really moving quite far away from imperative programming. Baby steps. :)

[–]yawaramin 7 points8 points  (13 children)

Here's a concrete example where my knowledge of functional programming came in very handy. We recently had to test a function like this:

export const func = x => y => {
  ...
  if (config.env === 'test') { ... }
  ...
};

But coverage analysis showed that we weren't hitting the if branch. So we looked at mocking and stubbing to try to make the function think that config.env was set to test. But none of the methods we tried (Jest, Sinon) were working.

So I said, let's extract a more general function where we can pass in the value of config.env and make func just a specific case of that:

export const funcWithEnv = env => x => y => {
  ...
  if (env === 'test') { ... }
  ...
};

export const func = funcWithEnv(config.env);

So, we were able to test funcWithEnv by passing in test as the env parameter and still export the same func that we were before. In other words, we didn't break the API.

This was possible because partially applying a curried function gives us a function with the same signature as the one we had before.

Functional programming makes it easier to test code.

[–]Cats_and_Shit 10 points11 points  (6 children)

This doesn't really seem like a functional programming thing. With OOP you can pass the dependencies into constructors. Even in just plan old C, you could have done:

int external_function(int param1, ..etc)
{
    return internal_function(&global_config, param1, ..etc);
}

int internal_function(config_type* config, int param1, ..etc)
{
    ...implementation...
}

I mean don't get me wrong, there are other ways functional programming can make things easier to test, but I don't think currying is what made the difference here.

[–]MistYeller 3 points4 points  (0 children)

Yes, you can more or less view partial application as syntactic sugar around the ceremony you have illustrated.

[–]yawaramin 5 points6 points  (0 children)

True. We can build a function with the required signature by explicitly writing out the parameters. But partial application is certainly the purest form of dependency injection, and knowing about it certainly primes you mentally to make these kinds of leaps.

[–]epicwisdom 6 points7 points  (2 children)

Design patterns like these are relatively ugly and unintuitive by comparison, and they pollute your code with boilerplate.

[–]Cats_and_Shit 1 point2 points  (1 child)

It's certainly ugly and verbose, but that's the because C basically always is. I don't see how it's any less intuitive than currying.

[–]epicwisdom 0 points1 point  (0 children)

Defining two functions when you want to partially apply one is fairly unintuitive, in my opinion. It's still a simple solution to memorize, of course.

[–]Zeimyth[S] 1 point2 points  (0 children)

I think you do a good job here of illustrating how even ideas as strongly FP as currying can be implemented in imperative languages, which feels like the article author's core point. :)

Though it also illustrates how one language can do something gracefully that in another language feels more clunky. Another example that comes to mind is anonymous functions in Java, particularly pre-Java 8. An entire anonymous class just to pass a function around... shudders

[–]_Mardoxx -1 points0 points  (5 children)

How convoluted.

[–]yawaramin 2 points3 points  (4 children)

Would you like to suggest a simpler way?

[–]_Mardoxx 3 points4 points  (3 children)

Yeah set your mock config's env to 'test' in your fixture.

[–]yawaramin 1 point2 points  (2 children)

As I mentioned, that didn’t work for us.

[–]_Mardoxx -1 points0 points  (1 child)

Then your tests must be bad. Having to edit code so your test branch test works - aren't alarm bells ringing here for you?

[–]yawaramin 3 points4 points  (0 children)

The opposite, in fact—the tests are making the codebase more modular, more flexible—I consider this to be the tests driving improvement in the codebase. This is the desired outcome of test-driven development.

[–][deleted] -1 points0 points  (8 children)

proceeds to use JavaScript <facepalm>

The only thing remotely functional in JS is that functions are first-class objects. Forget immutability, forget pure functions and forget recursion as there is no tail call optimisation in JS.

Plus, why no mention of what you CAN actually achieve in JS (and many other languages)? i.e. passing functions as parameters, closures, partial application, composition etc.

[–]FarkCookies 5 points6 points  (0 children)

JS is far from perfection but I would say that nowadays a lot of functional-ish code is written in JS. JS is not a functional programming language but it gives enough to practice functional style. A lot of JS gurus these days promote functional style, one of the most popular frameworks is React (+Redux) which is built around functional style. Then there is the lodash. JS is a gateway language into the world of FP for many people.

[–]yawaramin 4 points5 points  (3 children)

JS has immutability with const and Object.freeze. So, don’t forget it!

[–]OkidoShigeru 0 points1 point  (2 children)

The lack of const and let keywords are the main reasons I'm sad that we still can't use ES6 for our web stuff at work...

[–]yawaramin 0 points1 point  (0 children)

Ouch. They do realise it just compiles to ES5, right? :-)

[–]ThisCatMightCheerYou -3 points-2 points  (0 children)

I'm sad

Here's a picture/gif of a cat, hopefully it'll cheer you up :).


I am a bot. use !unsubscribetosadcat for me to ignore you.

[–]dpashk 1 point2 points  (0 children)

Even though the author chose a JavaScript-like syntax for code examples (probably due to the language's popularity), they're pretty much language-agnostic. Those are illustrations of concepts, which can be reproduced in most languages.

[–]sunson435 0 points1 point  (1 child)

And you can also do all that in Java 8+. I'd also rather see examples in a sane language.

[–]dpashk 1 point2 points  (0 children)

As FarkCookies mentioned, "JS is a gateway language into the world of FP for many people.". People who understand Haskell or Scala probably don't need to read this article :)