title: Nested Reduce Functions / Recursion / Functional Programming / Tree Traversal
body: <p>I keep running into situations where I end up nesting very many <code>reduce</code> functions to drill down into an object. It's hard to pull out the logic because at the bottom I need access to the various keys traversed along the way. Essentially, I'm looking for a better way to achieve the following:</p>
  
  <pre class="lang-js prettyprint-override"><code>import { curry } from 'lodash/fp'
  import { fromJS } from 'immutable'
  
  const reduce = curry((fn, acc, it) =&gt; it.reduce(fn, acc))
  
  describe('reduceNested', () =&gt; {
    const input = fromJS({
      a1: {
        b1: {
          c1: {
            d1: {
              e1: 'one',
              e2: 'two',
              e3: 'three'
            },
            d2: {
              e1: 'one',
              e2: 'two',
              e3: 'three'
            }
          },
          c2: {
            d1: {
              e1: 'one',
              e2: 'two'
            }
          }
        }
      },
      a2: {
        b1: {
          c1: {
            d1: {
              e1: 'one'
            },
            d2: {
              e1: 'one'
            }
          }
        },
        b2: {
          c1: {
            d1: {
              e1: 'one'
            },
            d2: {
              e1: 'one'
            }
          }
        }
      },
      a3: {
        b1: {
          c1: {}
        }
      }
    })
  
    const expected = fromJS({
      one: [
        'a1.b1.c1.d1.e1',
        'a1.b1.c1.d2.e1',
        'a1.b1.c2.d1.e1',
        'a2.b1.c1.d1.e1',
        'a2.b1.c1.d2.e1',
        'a2.b2.c1.d1.e1',
        'a2.b2.c1.d2.e1'
      ],
      two: ['a1.b1.c1.d1.e2', 'a1.b1.c1.d2.e2', 'a1.b1.c2.d1.e2'],
      three: ['a1.b1.c1.d1.e3', 'a1.b1.c1.d2.e3']
    })
  
    const init = fromJS({ one: [], two: [], three: [] })
  
    test('madness', () =&gt; {
      const result = reduce(
        (acc2, val, key) =&gt;
          reduce(
            (acc3, val2, key2) =&gt;
              reduce(
                (acc4, val3, key3) =&gt;
                  reduce(
                    (acc5, val4, key4) =&gt;
                      reduce(
                        (acc6, val5, key5) =&gt;
                          acc6.update(val5, i =&gt;
                            i.push(`${key}.${key2}.${key3}.${key4}.${key5}`)
                          ),
                        acc5,
                        val4
                      ),
                    acc4,
                    val3
                  ),
                acc3,
                val2
              ),
            acc2,
            val
          ),
        init,
        input
      )
  
      expect(result).toEqual(expected)
    })
  
    test('better', () =&gt; {
      const result = reduceNested(
        (acc, curr, a, b, c, d, e) =&gt;
          acc.update(curr, i =&gt; i.push(`${a}.${b}.${c}.${d}.${e}`)),
        init,
        input
      )
  
      expect(result).toEqual(expected)
    })
  })
  </code></pre>
  
  <p>I would like to write a function <code>reduceNested</code> that achieves the same result but without all of the nested reduce functions. I don't see something in <code>lodash/fp</code> or similar to address so my thought was to create a new function <code>reduceNested</code> and to add variables to the callback for each key in the tree. I've tried implementing the actual logic but am unfortunately stuck for the time being. I know <code>reduceNested</code> will need to use <code>fn.length</code> to determine how far down into the source to drill, but other than that I'm just stuck.</p>
  
  <pre class="lang-js prettyprint-override"><code>const reduceNested = curry((fn, acc, iter) =&gt; {
    // TODO --&gt; use (fn.length - 2)
  })
  </code></pre>