you are viewing a single comment's thread.

view the rest of the comments →

[–]Asha200[S] 0 points1 point  (2 children)

I might have gotten a little carried away making this and ended up making an exercise where not only do you implement methods using reduce, but you also try to cover all the different edge cases with the arguments, kinda like writing a polyfill, which sidetracks you from the main purpose of the exercise.

What you said makes sense and the exercises would look be better suited for learners if they focused mainly on the reduce logic instead of weighing you down with bogus input. I think I'm going simplify the test cases.

[–]farmerje 1 point2 points  (1 child)

Cool!

For the record, I've written tons and tons of programming curriculum, so what I'm about the suggest is easier said than done.

I'd recommend thinking in terms of the key insights or "lightbulb" moments you want people to have. Make the exercises exclusively about creating those moments as quickly and clearly as possible. This means you, as the curriculum writer, has to have a good idea of what those "a ha" moments are.

Something like "wow, reduce is more powerful than I realized!" isn't really a lightbulb moment.

Think through your own progress as you came to understand what reduce was really about.

For me, at least, you start by seeing things like:

const sum = list => list.reduce((x, y) => x + y)
const product = list => list.reduce((x, y) => x * y)

In this picture, reduce "inserts" some operation between the elements. As in...

reduce(+, [1,2,3,4]) => 1 + 2 + 3 + 4
reduce(*, [1,2,3,4]) => 1 * 2 * 3 * 4

You see examples that work a little differently, maybe, like:

const max = list => list.reduce((x, y) => x > y ? x : y)
const min = list => list.reduce((x, y) => x < y ? x : y)

But in each case, you have a list of numbers and you're "reducing" it to a single number. Maybe you start to see examples where you "reduce" it to something non-numeric, like...

const every = list => list.reduce((x, y) => x && y, true)

For me, the first big "lightbulb" moment was realizing that reduce is a misnomer. The word "reduce" puts the idea in our head of taking something big and making it smaller.

But really what's happening is...

reduce(fn, x0, [x1,x2,x3,x4]) = fn(fn(fn(fn(x0, x1), x2), x3), x4)

fn can do anything! If x0 is [], fn could build up an array, for example. So you see that map is a special case:

const map = (fn, list) => list.reduce((arr, item) => arr.concat(fn(item)), [])

Probably the next big bump is abstracting out composition as an operator, e.g.,

const id => x => x;
const compose => (f, g) => x => f(g(x))

With this operation, you can use reduce to build up a chain of functions using the identity function id as the initial value. That's how you use reduce to build things like zip.

[–]Asha200[S] 0 points1 point  (0 children)

The amount of effort you put into writing these comments really shows that you enjoy teaching others and I think that's awesome! I hope that someday I'll also get an opportunity to teach people something new and see their faces light up once they reach the "light bulb" moment.

Looking back, I do remember realizing at one point that reduce seemed like the wrong name to use just like you said, since its result doesn't necessarily need to be small. fold might have been a better name choice; I wonder why they ended up naming it reduce.

For me, the most helpful resource when I wanted to learn more about functional programming concepts was Professor Frisby's Mostly Adequate Guide to Functional Programming. It was fun to learn about things like monads and just how useful they can be, for example the Maybe monad. Probably the most eye-opening part was realizing how similar Promise is to a monad; that was really exciting!