
Javascript Arrays and Functional Programming - zabana
http://zabanaa.github.io/notes/functional-programming-and-javascript-arrays.html
======
seanwilson
I accept that this is a widely used phrase now but I never understood why just
using map/filter/reduce and avoiding state is enough for code to be called
"functional programming".

Most functional languages feature pattern matching, algebraic data types,
purity, currying, strong typing, type inference, recursion instead of loops
and types that cannot be null. It's a completely different style of coding.
Adding map/filter/reduce to an imperative language doesn't get you close to
the level of robustness and ease of implementation for that safety you'd get
in a functional language.

~~~
hacker_9
Wiki sums up the term well enough:

 _" In computer science, functional programming is a programming paradigm — a
style of building the structure and elements of computer programs — that
treats computation as the evaluation of mathematical functions and avoids
changing-state and mutable data."_

To that end map-reduce fits and can be referred to as 'functional
programming'. The other things you mention are just great language features,
but not specific to functional languages. Imperative C++ also has type safety,
Swift has non-null types, etc.

~~~
seanwilson
> The other things you mention are just great language features, but not
> specific to functional languages. Imperative C++ also has type safety, Swift
> has non-null types, etc.

All those features in combination are shared by the vast majority of languages
called functional programming languages. They're pretty much the defining
features of functional languages was my point. Other languages can have a
subset of the features but it doesn't make them functional languages. See:
[https://wiki.haskell.org/Functional_programming](https://wiki.haskell.org/Functional_programming)

The Wikipedia quote is really vague.

~~~
dahart
None of pattern matching, algebraic data types, strong typing, type inference
and types that can't be null are specific to functional, nor do they make it
any more functional. Purity isn't a language feature, it's a measure of how
functional a language is, so it's tautological to say functional languages
share purity. Currying is a byproduct of first class functions, not of
functional programming, and currying is common in JavaScript and Python and
other non-functional languages including C++. Forced recursion instead of
loops would just be a byproduct of not having mutable state. And a good
alternative to a recursive loop is a call to map() or reduce().

> The Wikipedia quote is really vague.

I think the Wikipedia quote is clearer and FAR more precise than a common
feature set. Functional programming "treats computation as the evaluation of
mathematical functions and avoids changing-state and mutable data." That is
the definition of functional, and it's the _whole_ definition. No mutation,
that's it. Including the features you wrote about is not functional
programming, it's other things.

That's important to consider the precise definition if you're going to
critique someone for talking about functional programming in a certain way.
The author was pretty clear that this is functional programming concepts as
applied to arrays in JavaScript, he never claimed that this post covers
functional programming in general.

Map, filter & reduce are examples of functional programming, and if they were
all you used, and you had only const and no var, then you might have a
functional program. @zabana didn't claim that this is all you'll ever need.

~~~
seanwilson
> Functional programming "treats computation as the evaluation of mathematical
> functions and avoids changing-state and mutable data." That is the
> definition of functional, and it's the whole definition. No mutation, that's
> it. Including the features you wrote about is not functional programming,
> it's other things.

Are you meaning that "no mutation" is the definition of functional
programming? That's such a vague definition I can't see how it is useful
personally. "Stateless" is already a word that covers that.

If you're going to quote Wikipedia, keep going to the "Concepts" section that
lists language features: "A number of concepts and paradigms are specific to
functional programming, and generally foreign to imperative programming
(including object-oriented programming). However, programming languages are
often hybrids of several programming paradigms, so programmers using "mostly
imperative" languages may have utilized some of these concepts.[40]"

> The author was pretty clear that this is functional programming concepts as
> applied to arrays in JavaScript, he never claimed that this post covers
> functional programming in general.

I even said I accept it's common usage of the phrase and I was just wondering
why that was.

~~~
dahart
> Are you meaning that "no mutation" is the definition of functional
> programming?

You can see that I was intentionally summarizing wikipedia's definition in one
word to make my point more clear that functional does not mean type inference
or currying, right?

> That's such a vague definition I can't see how it is useful personally.
> "Stateless" is already a word that covers that.

Since I'm not offering "immutable" as the complete and final definition for
functional programming, maybe you can find a better one to make your original
point clear? Because the list of features you offered as defining functional
programming doesn't define functional programming very well.

IMO, the entire first paragraph of Wikipedia's article on functional
programming is pretty good. It repeats the concept of immutability in a bunch
of different ways with clarifying examples, to make it more concrete and less
vague.

I don't personally like "stateless" because it's not strictly true. Functional
programs have state, and the state is contained in the stack. The point of
functional programming is that the language avoids side effects, and the most
direct word for something that avoids side effects is "immutable", not
"stateless". I can accept that common usage of stateless is sometimes
referring to immutability.

Note that WP's definition of "state" agrees with that, and talks about
declarative state being indirect, as opposed to being stateless: "In
declarative programming languages, the program describes the desired results
and doesn't specify changes to the state directly."

[https://en.wikipedia.org/wiki/State_(computer_science)](https://en.wikipedia.org/wiki/State_\(computer_science\))

> I even said I accept it's common usage of the phrase and I was just
> wondering why that was.

Because it's true and meets the definition? Your objection is too vague. What,
exactly, is wrong with calling map/filter/reduce "functional"? In my book,
referring to map as an example of functional programming doesn't stretch the
strict definition of functional programming _at all_.

map() and reduce() were some of the very first things I learned about when I
was introduced to the concept of functional programming in Scheme, more than
20 years ago.

The post didn't claim that map, filter & reduce were 'enough for code to be
called "functional programming"'. He only ever implied that map, filter &
reduce are _part_ of functional programming. That is absolutely true, always
has been, and isn't a matter of common usage.

------
zabana
Author here: I wrote this article mainly as a note to self that I could refer
to in the future and as an exercise to help me learn the concept and force me
to structure my thoughts into a coherent blog post. I thought I'd share it for
those of us who are more intermediate and would like to pick up a few tricks
along the way. Thank you all for the positive (and not so positive feedback)

~~~
dberhane
Reading your blog allowed me to better understand the reduce function for the
first time and I want to thank you for that.

------
Kiro
I don't know if I'm delirious but I remember a few years ago when articles
like this were very common on HN. Then all of a sudden it felt like everyone
had "learnt" it and all that got upvoted was very complicated articles
explaining some esoteric JS thing.

Now it seems we're back again with. Another example is the article explaining
"this" which is on the front page again. It almost feels cyclic, like it's
time for the new generation of programmers to learn the quirks.

It's probably an incorrect observation but it feels like the front page has
developed with me. Like we all started on square 1, evolved together and now
it's time to graduate and leave room for the new generation.

~~~
supermdguy
Maybe hacker news is starting to gain popularity with students, who are trying
to follow the "pro hackers".

------
drinchev
Some more practical examples

    
    
        // Grab unique
        [1,1,2,3,4].filter( ( item, index, array ) => array.indexOf( item ) === index )
        // => [1,2,3,4] 
    
        // Flatten
        [[1,2],[3,4]].reduce( ( result, item ) => result.concat(item), [] );
        // => [1,2,3,4]
    

Not sure why the author missed `sort`.

    
    
        // Sort
        [1,2,4,3].sort( ( a, b ) => a - b )

~~~
Veedrac
The first is slow (O(n²) where O(n) will do), and the second is very likely to
be slow (probably the same).

~~~
drinchev
The good old question about sacrificing performance for readability. Anyway
these days filter is not so bad.

[1] [https://jsperf.com/array-uniq-filter](https://jsperf.com/array-uniq-
filter)

~~~
Veedrac
And insertion sort is not so bad with 20 elements. It doesn't take much for it
to start falling over, though.

[1]: [https://jsperf.com/array-unique-filter-2/1](https://jsperf.com/array-
unique-filter-2/1)

------
nerdponx
JavaScript has an advantage on Python in this style, because Python lambdas
are hideously ugly and JS anonymous functions are less hideously ugly. In
Python it tends to be cleaner (and sometimes faster) to write list
comprehensions instead of map() and filter(), especially since Python also has
lazy generator comprehensions.

~~~
pryelluw
Python actually discourages using map anf filter. Which is kind of weird to me
but whatever.

~~~
nerdponx
Well in some cases it really is more efficient.

    
    
        [func(x) if x in collection if cond(x)]
    

makes a single pass over the data and gives you a list, but

    
    
        list(map(func, filter(cond, collection)))
    

makes two passes _and_ requires some extra function calls.

I think the real reason is perceived legibility on the part of the Python core
devs. I seem to recall a document from a while ago in which GvR himself came
out in favor of list comprehension style. "Explicit is better than implicit".

~~~
nitroll
Both map and filter returns an iterator, so you only iterate once when
creating the list.

------
Blackstone4
Thank you for this! I've been learning JS for React and .reduce, .every and
.some are new to me! Super helpful

------
cygned
As a side note, using .push() isn't something I would consider being
functional because immutability is a core concept of functional programming.

Too bad, JavaScript makes it hard to do it that way, in that concrete example
using Object.assign() and .concat().

~~~
jlg23
> immutability is a core concept of functional programming.

That depends very much on your definition of FP (or how "pure" the FP is,
depending on your definition of "purity").

~~~
cygned
Fair point. All my touch points (Lisp, JavaScript, even a bit Haskell and
several books) all proposed immutability as being a fundamental principle.

Would you mind expanding a bit on that point in case I totally misunderstood
something?

~~~
jlg23
You did not "totally misunderstand something": Immutability is a virtue in FP,
you _should_ write in this style. But it is only a "fundamental principle" and
"core concept" in _highly pure_ languages - and even Haskell allows mutable
variables[1].

Sometimes you just need them, e.g. when handling potentially very large
vectors in finite memory. CL's (sort ...) for example mutates the input
sequence (or "destructively sorts" it [2]).

[1]
[https://wiki.haskell.org/Mutable_variable](https://wiki.haskell.org/Mutable_variable)
[2]
[http://www.lispworks.com/documentation/HyperSpec/Body/f_sort...](http://www.lispworks.com/documentation/HyperSpec/Body/f_sort_.htm)

------
jaunkst
For more fun with FP checkout lodash fp
[https://github.com/lodash/lodash/wiki/FP-
Guide](https://github.com/lodash/lodash/wiki/FP-Guide)

Also read about using flow over chain

------
namanyayg
Great article, but questionable formatting: `return {name: player.name, age:
player.age }`

It also seems _wrong_ to mutate the accumulator in the reduce example, it
would just be simpler to use `forEach` and use a variable defined outside if
you're going to write code this way?

~~~
drinchev
Wouldn't do it with variable, since it will make your function impure [1]

1 : [http://www.nicoespeon.com/en/2015/01/pure-functions-
javascri...](http://www.nicoespeon.com/en/2015/01/pure-functions-javascript/)

~~~
pdpi
That's the GP's point though: it already is impure! If you rewrite as

    
    
        let acc = {...}
        footballPlayers.reduce(...,acc)
    

It should become clear: acc is an external variable that got mutated by the
reduce.

~~~
bestest
Indeed. A pure function should not depend on and / or mutate external
variables.

I'd do it like this (yay for one-ish-liners!):

    
    
      const playersByCountry = footballPlayers.reduce((acc, player) => {
        return {...acc, [player.country]: [...(acc[player.country] || []), player]};
      }, {});

------
guiomie
In his example Array.prototype.reduce, isn't this almost the same as just
doing a foreach loop? I don't understand why doing this, it's pretty much the
same number of lines.

~~~
ablomen
In this example it is, but a nice thing about using map, reduce etc is that
you can chain them together, ex:

    
    
      let out = ["a", "b", "c", 1, 2, 3]
      	// Turn letters to upper case
      	.map(i => {
      		return typeof i === "string"
      			? i.toUpperCase()
      			: i;
      	})
      	// Add one to numbers
      	.map(i => {
      		return typeof i === "number"
      			? i + 1
      			: i;
      	})
      	// split letters and numbers up
      	.reduce((all, i) => { 
      		typeof i === "string"
      			? all.letters.push(i)
      			: all.numbers.push(i);
      		return all;
      	}, { "letters": [], "numbers": [] });
      // => { letters: ["A", "B", "C"], numbers: [2, 3, 4] }

~~~
moosingin3space
The problem with this is that it generates two intermediate arrays in the
maps, then effectively drops them in the reduce. This may be inefficient.

I wish that JavaScript's map/filter/reduce functions returned lazy iterators,
like in Rust, so that code like this doesn't produce intermediate arrays. Does
anyone know of a library that provides this?

~~~
marmart
Those intermediate iterations could be dropped by composing the map functions
together (same with the reduce), if that really was a performance bottleneck.

~~~
moosingin3space
With lazy iterators, there is the possibility of better composition of
maps/filters/reduces. That's why I'm a fan of the lazy iterators approach --
otherwise the abstraction breaks too easily and it ends up looking like a for-
loop anyway.

------
sbr464
I noticed you used let to instantiate variables. Should switch to const, and
if really going functional, will begin to find few rare cases where let is
needed.

------
sleazybae
this post introduced me to the arrow function
(([https://stackoverflow.com/questions/24900875)](https://stackoverflow.com/questions/24900875\))),
which i'd previously not heard of. evidently it was introduced in ECMAscript 6
but for engines that use JavaScript and older browsers (amazingly, they still
exist) it won't work

~~~
dave7
There is a spurious ) ending your link, resulting in page not found error.

For those using arrow functions these days for web, most will use Babel in the
build process to provide compatibility with older platforms.

------
arkadiytehgraet
TL;DR author provides an example of map, filter and reduce functions in JS.

I have been wondering lately what is the value of articles like this. They do
not convey any meaningful idea, they do not offer any useful insight on
underlying matters; why do people even write something like this, except to
litter the Internet even more? Anyone, who is distinctly familiar with
functional programming or even just with the concept of higher order
functions, surely knows those three basic primitives; those, who are not,
would benefit much more from the basic concepts of first-class functions etc,
than this random abrupt post.

~~~
kaishiro
Man, I had just worked up the nerve to start a personal dev blog but you've
just scared me straight off.

~~~
arkadiytehgraet
I have wanted to start a personal dev blog myself for quite a while, but each
time I think of a suitable topic, I immediately recall an article or a post
that is already better than anything I could write myself on the matter.

If you think you have something valuable or interesting or just funny to
share, that either was never discussed or written about or you know you can do
better, then you absolutely should blog about it and do not let haters like me
stop you.

As for the original article:

* It should have been named just "JavaScript arrays and higher-order functions" (I get that using term _functional programming_ is very catchy nowadays, but I am trying to talk about quality here, not clickbaitness)

* As it is aimed for people unfamiliar with the concept and coming from more imperative background, where first-class functions are either not present or not that popular or handy to work with, an introduction (even the most gentle one) would be very suitable

* Then the introduction of filter/map/reduce functions would be in place, ideally compared in place with imperative implementation of the same task

* The best way to make sure a reader understands how each of this functions works is to make them implement each one of them, even the naive implementation would suffice

* Finally, you could provide some reasonably unobvious usages of any of the functions, e.g. insertion sort done with fold-only.

~~~
Can_Not
> I have wanted to start a personal dev blog myself for quite a while, but
> each time I think of a suitable topic, I immediately recall an article or a
> post that is already better than anything I could write myself on the
> matter.

Sounds like you should be curating a list.

------
matlin
This hardly covers any functional patterns that javascript is capable of. You
can compose functions, avoid stack overflows in tail call recursion, use
immutable values, etc. I've seen articles on pattern matching with Typescript
or trampolining code but this is simple a descriptive look at three basic
javascript functions. If you're interested in more of a functional approach in
JS take a look at Immutable.js and/or [https://pattern-matching-with-
typescript.alabor.me/](https://pattern-matching-with-typescript.alabor.me/).

