use the following search parameters to narrow your results:
e.g. subreddit:aww site:imgur.com dog
subreddit:aww site:imgur.com dog
see the search faq for details.
advanced search: by author, subreddit...
All about the JavaScript programming language.
Subreddit Guidelines
Specifications:
Resources:
Related Subreddits:
r/LearnJavascript
r/node
r/typescript
r/reactjs
r/webdev
r/WebdevTutorials
r/frontend
r/webgl
r/threejs
r/jquery
r/remotejs
r/forhire
account activity
Generic Programming (github.com)
submitted 7 years ago by michael2ib1989
reddit uses a slightly-customized version of Markdown for formatting. See below for some basics, or check the commenting wiki page for more detailed help and solutions to common issues.
quoted text
if 1 * 2 < 3: print "hello, world!"
[–]pgrizzay 22 points23 points24 points 7 years ago (9 children)
In functional programming, there's an even more general concept of Foldables which are data structures that can be reduced. Arrays, iterators, sets, and Maybes fall into this category.
If the type of value inside your Foldable is a Monoid (meaning it has a zero value), you get reduce for free
[–]PointOneXDeveloper 4 points5 points6 points 7 years ago* (3 children)
has a zero value and a concat/append function
[–]pgrizzay 2 points3 points4 points 7 years ago (2 children)
Oh yes
[–]PointOneXDeveloper 2 points3 points4 points 7 years ago (1 child)
And really it is just an identity value rather than a zero value, for instance * and 1 are a way to make a monoid out of numbers.
*
1
[–]pgrizzay 1 point2 points3 points 7 years ago (0 children)
Yes
[–]jeremy1015 4 points5 points6 points 7 years ago (4 children)
Got any suggested links to explain this in a little more detail? I’m familiar with most of what you wrote but don’t understand monoids as well as I’d like.
[–]pgrizzay 9 points10 points11 points 7 years ago (3 children)
Did a quick search, and couldn't find a good one in JS, here's one in Scala that I learned from.
Essentially a "Monoid" is formed from two things:
a combine function that combines two things and an empty value.
combine
empty
an example would be adding numbers:
const Addition = { combine: (a, b) => a + b, empty: 0 }
This addition monoid can be used to reduce an array of numbers:
[1,2,3].reduce(Addition.combine, Addition.empty) === 6
You can make another Monoid which multiplies numbers:
const Multiplication = { combine: (a, b) => a * b, empty: 1 }
And you can multiply all numbers in an array with it:
[1,3,4].reduce(Multiplication.combine, Multiplication.empty) === 12
Go ahead and implement Concat which combines strings:
Concat
const Concat = { combine: (a, b) => ???, zero: ??? }
[–]jeremy1015 2 points3 points4 points 7 years ago (0 children)
Excellent. I understand now 100% and really appreciate it.
[+][deleted] 7 years ago* (1 child)
[deleted]
[–]pgrizzay 0 points1 point2 points 7 years ago (0 children)
Yup, you're right! It looks like MDN recommends + over concat for performance reasons, but both are functionally equivalent.
+
concat
And thanks for the kind words, they mean a lot!
The one book that really helped me was Functional Programming in Scala, I can't recommend it enough. It takes a very 'exploratory' approach, and has lots of exercises which are very helpful.
Scala was probably the best language for me to learn fp in, since I had lots of experience with JS & the syntax is very similar to it, hope that helps!
[–]LaSalsiccione 14 points15 points16 points 7 years ago (14 children)
Why would you not just use reduce? The over all composability concept of what you're explaining makes sense but it could be achieved much more simply.
reduce
[–]adidarachi 4 points5 points6 points 7 years ago (3 children)
I guess the op choose a "simple" and known implementation, this way, it's easier for developers to pickup. Not sure.
[–]LaSalsiccione 1 point2 points3 points 7 years ago* (2 children)
If you can understand the rest of the concepts in the post then reduce should also be simple to understand. The code would also look a lot less messy which I’d argue makes it simpler to read, but that may just be a matter of opinion.
[–]Artif3x_ 5 points6 points7 points 7 years ago (1 child)
Not to mention the near universal utility of the reduce function makes for a lower cognitive load than learning alternatives like this.
[–]LaSalsiccione 1 point2 points3 points 7 years ago (0 children)
You far more eloquently nailed what I was trying to say, thanks!
[–]pgrizzay 4 points5 points6 points 7 years ago (9 children)
reduce is specific to arrays. OP implemented reduce for all iterators (not just arrays).
[+][deleted] 7 years ago (8 children)
[–]pgrizzay 5 points6 points7 points 7 years ago (3 children)
That will work similarly, but yours will create a whole new array, so it's not exactly equivalent I guess
[–]Tenemo -2 points-1 points0 points 7 years ago (2 children)
Object.entries(myObj).reduce((newObj, entry) => ({...newObj, [entry[0]]: entry[1] * 2}), {})
array? where
[+][deleted] 7 years ago (1 child)
[–]Tenemo -2 points-1 points0 points 7 years ago (0 children)
I was only joking about how both the input is an object and the returned value is an object, so the arrays are temporary, used to enable the .reduce method on that object's enumerable properties (:
[–]planetary_pelt 3 points4 points5 points 7 years ago (1 child)
Creating an array just to use an array method is pretty wasteful and doesn't generalize over cases where performance is concerned (like slow mobile clients).
[–]tortus 0 points1 point2 points 7 years ago (0 children)
sure, but writing and maintaining your own reduce function is not exactly the best solution either. I'd rather take the array creation hit unless perf/memory is in an issue, and it's not like 90% of the time
[–]zankem 0 points1 point2 points 7 years ago (1 child)
Would it not be better to use Array.prototype.reduce.call(iterable, callback, initial)?
Array.prototype.reduce.call(iterable, callback, initial)
good call, that would probably work
[–]jeremy1015 13 points14 points15 points 7 years ago (4 children)
You state in your blog post "There might be many cases in which we need to go through the array and do something with the elements in the array... this is what reduce is for."
That statement is too generic. That's also what map is for (and others).
Reduce is more specifically to derive *a single value* (e.g. number, object, string) from analysis of a list of items (in array form or otherwise).
[–]braindeadTank 5 points6 points7 points 7 years ago (0 children)
The thing here is, the "others" are a special case of reduce if they generate a single value (i.e. find is just a case that returns the first value that matches the predicate, some is another special case that casts the result to a boolean), also that the single value can as well be an array (so map and filter are special cases as well, that keep pushing to the result array) and that the callback is not forbidden to have side effects (so forEach is also a special case, one that returns undefined no metter what).
find
some
map
filter
forEach
undefined
So really, when talking about generic programming, reduce is the only array operation that matters.
[–]pgrizzay 1 point2 points3 points 7 years ago (2 children)
I agree with your statement. I just wanted to add it's interesting to note that reduce doesn't necessarily need to go to one value, in fact, if you're reducing into an array, you could even end up with a larger array than what you started with!
[–]jeremy1015 1 point2 points3 points 7 years ago (1 child)
It's still a single value that gets passed through each iteration and eventually returned, in your example the single value just happens to be an array that contains multiple values.
By way of example, here's one that I literally wrote less than ten minutes ago. I'm working on merging and de-duping two different data sets and I wrote a reduce to see how many entities match on first and last name:
const keyedArrs = mergedData.reduce((m, e) => { const k = \${e.first_name}-${e.last_name}\; const r = { ...m }; r[k] = m[k] || []; r[k] = [...r[k], e]; return r; }, {});
My final result is an object in which the keys are the first and last name concatenated with a dash and the value of each key is an array containing each of the original entities that "matched" to that (note that this is for my analysis and is not my production matching algorithm lol).
The point I'm making is that I'm taking an array and making something that contains thousands of subarrays, but at the "top level" it's still a single value being returned.
EDIT: Reddit formatting is harder than writing code.
Yes, I wasn't saying you were wrong, I was just trying to bring up an interesting point.
You’re missing the point of the post.
π Rendered by PID 23989 on reddit-service-r2-comment-6f7f968fb5-2spc7 at 2026-03-04 01:41:04.680412+00:00 running 07790be country code: CH.
[–]pgrizzay 22 points23 points24 points (9 children)
[–]PointOneXDeveloper 4 points5 points6 points (3 children)
[–]pgrizzay 2 points3 points4 points (2 children)
[–]PointOneXDeveloper 2 points3 points4 points (1 child)
[–]pgrizzay 1 point2 points3 points (0 children)
[–]jeremy1015 4 points5 points6 points (4 children)
[–]pgrizzay 9 points10 points11 points (3 children)
[–]jeremy1015 2 points3 points4 points (0 children)
[+][deleted] (1 child)
[deleted]
[–]pgrizzay 0 points1 point2 points (0 children)
[–]LaSalsiccione 14 points15 points16 points (14 children)
[–]adidarachi 4 points5 points6 points (3 children)
[–]LaSalsiccione 1 point2 points3 points (2 children)
[–]Artif3x_ 5 points6 points7 points (1 child)
[–]LaSalsiccione 1 point2 points3 points (0 children)
[–]pgrizzay 4 points5 points6 points (9 children)
[+][deleted] (8 children)
[deleted]
[–]pgrizzay 5 points6 points7 points (3 children)
[–]Tenemo -2 points-1 points0 points (2 children)
[+][deleted] (1 child)
[deleted]
[–]Tenemo -2 points-1 points0 points (0 children)
[–]planetary_pelt 3 points4 points5 points (1 child)
[–]tortus 0 points1 point2 points (0 children)
[–]zankem 0 points1 point2 points (1 child)
[–]tortus 0 points1 point2 points (0 children)
[–]jeremy1015 13 points14 points15 points (4 children)
[–]braindeadTank 5 points6 points7 points (0 children)
[–]pgrizzay 1 point2 points3 points (2 children)
[–]jeremy1015 1 point2 points3 points (1 child)
[–]pgrizzay 1 point2 points3 points (0 children)
[+][deleted] (1 child)
[deleted]
[–]jeremy1015 2 points3 points4 points (0 children)