2

I am stuck on a problem on an online course that I am trying to explain this to myself. I understand what the "compose" function/ idea does in a simpler format but when it comes to applying reduce for a factory of functions and running compose on each function seems to be confusing to me. Hoping someone with experience can explain to me more clearly what is going on in terms of the "return fns.reduce(compose)" line and how it implements these functions one at time? Is each function taking turns being the "Accumulator" and then the "current" in reduce once the function is invoked at the bottom?

const user = {
    user: 'Jennnifer',
    active: true,
    cart: [],
    purchases: []
}


const compose = (f, g) => (...args) => f(g(...args));

function purchaseItem(...fns){
    return fns.reduce(compose)
    // return Object.assign({}, user, {purchases: item})
}

//Receives a user, and the item
function addItemToCart(user, item){
    //Create a variable and concat the empty cart of the user object to add the item to the cart key.
    const updateCart = user.cart.concat(item);
    return Object.assign({}, user, { cart: updateCart });
}

function applyTaxToItems(user){
    const { cart } = user;
    const taxRate = 1.3;
    const updatedCart = cart.map(item => {
        return {
            name: item.name,
            price: item.price * taxRate
        }
    })

    return Object.assign({}, user, { cart: updatedCart})
}

function buyItem(user){
    return user
}

function emptyCart(user){
    return user
}

//Invoke Function:

console.log(purchaseItem
    (
        emptyCart,
        buyItem,
        applyTaxToItems,
        addItemToCart
    )(user, { name: 'Laptop', price: 200})
)

2 Answers 2

2

Your function names is a little bit off

basically your compose function is compose for only 2 functions

your purchaseItem function actually not purchasing anything. If you look closely, you can see that it just returns composition of N functions

Basically, on each step of reduce, you compose your current function with accumulator — all composed functions from before

And if it's step 0 (there is no before), then it gonna compose first two functions and put it to accumulator

Better rename it:

compose -> compose2

purchaseItem -> compose

then in last console.log() where you doing

purchaseItem
    (
        emptyCart,
        buyItem,
        applyTaxToItems,
        addItemToCart
    )(user, { name: 'Laptop', price: 200})

for better understanding you can write it like that

// composition of 2 functions
const compose2 = (f, g) => (...args) => f(g(...args))

// composition of N functions
const compose(...fns) => fns.reduce(compose2)

// applying composition to 4 functions
const purchaseItem = compose(
        emptyCart,
        buyItem,
        applyTaxToItems,
        addItemToCart
)

// calling 
purchaseItem(user, { name: 'Laptop', price: 200})

Sign up to request clarification or add additional context in comments.

1 Comment

Interesting.. I wonder why the argument "f" is the emptyCart function and "g" represents the rest of the other functions? I console logged f and g from the compose and saw that in my editor. Quite mysterious.
2

The above answer is good enough, but for more logical understanding reduce method of the compose function.

// reduce return : (...args) => prev(curr(...args));
// f'     : (...args) => f(g(...args));
// f''    : (...args) => f'(h(...args));    (...args) => f(g(h(...args))) 
// f'''   : (...args) => f''(j(...args));   (...args) => f(g(h(j(...args)))) 
// f''''  : (...args) => f'''(k(...args));  (...args) => f(g(h(j(k(...args)))))

function compose(f, g) {
  return function(...args) {
    return f(g(...args))
  }
}

function composeAll(...fns) {
  return fns.reduce(compose) // return function is (...args) => f(g(h(j(k(...args)))))
}

function f(x) {return x+'1'}
function g(x) {return x+'2'}
function h(x) {return x+'3'}
function j(x) {return x+'4'}
function k(x) {return x+'5'}

let result = composeAll(k, j, h, g, f)('cho');
console.log(result); // cho12345

The first five comment lines explain what happens to reduce return value of composeAll function.

f'' : (...args) => f'(h(...args)); (...args) => f(g(h(...args)))

means that (...args) => f'(h(...args)) is same as (...args) => f(g(h(...args)))

and I represent these as f'

You need to distinct reduce callback function, f, g(line 9) in reduce callback function is not the same value with composeAll's f and g arguments (line 14)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.