Struggling to understand Function composition in Coordinate Transformation exercise

Im really struggling with the 3rd task in the coordinate transformation exercise. In which i am asked to:

Combine two transformation functions to perform a repeatable transformation. This is often called function composition , where the result of the first function ‘f(x)’ is used as the input to the second function ‘g(x)’

I think understand concept behind function composition. chaining together functions by return a function within a function. however I am still stuck with how to implement them given the code:

const moveCoordinatesRight2Px = translate2d(2, 0);

const doubleCoordinates = scale2d(2, 2);

const composedTransformations = composeTransformation(

moveCoordinatesRight2Px,

doubleCoordinates

);

const result = composedTransformations(0, 1);

// result => [4, 2]

so far in my journey ive tried to visualize what is happening with the code to get an understanding of whats happening so i can figure out where to start, however i cant seem to visualize what the code is actually doing. So i cant even begin to figure out how to implement a solution

Does anyone have any resources regarding function composition they can refer me? All the resources I’ve found so far reinforce the conceptual idea but i cant seem to move beyond that. I also have a feeling that my inability to grasp this is because im not 100% with closures.

This is for the Coordinate Transformation exercise on the JavaScript track, right?

Yes that’s the exercise

Function composition and closures are orthogonal concepts, i.e. ‘unrelated’, so this is not the cause of your trouble.

I have a few questions for you:

  • Did you notice that translate2d and scale2d return functions (as opposed to numbers or arrays or …)?

  • Did you notice that composeTransformation takes two functions as arguments (and should return a function)?

Thanks for clarifying that function Composition are separate from closures. I did realize that translate2d and scale2d are returning functions, however, that’s where my mind goes to mush. I do not fully understand what the returned functions are doing with their passed variables

EDIT: For my terrible grammar

This is a common occurrence :stuck_out_tongue:

Might be one of them developmental milestones. (Along with variables, recursion, polymorphism, …)

Don’t worry; it’ll clear up.

You did successfully write trasnlate2d and scale2d, right? (If so, and you are having trouble understanding their implementation, feel free to post the code.)

I’m guessing a hypothetical

const doubledCoordinates = scale2d(2, 2, x, y);

strikes you as a more familiar style. Having scale2d instead return a function (as required) changes this into

const doubledCoordinates = scale2d(2, 2)(x, y);

which does look odd. However, there is a benefit: the scale2d(2, 2) part could be extracted and reused:

const doubleCoordinates = scale2d(2, 2);
const someResult    = doubleCoordinates(2, 3);
const anotherResult = doubleCoordinates(8, 4);

Ok, so I just figured it out moments ago, thanks to VS variable watch debug feature! I think my confusion came from a lack of a real understanding of how closures work and the purpose of the outer function. Also, being able to watch the code at each step greatly helped my understanding.

Forgive me for trying to explain it so I can make sure I understand it myself, lol.

My first issue was failing to realize that all the outer function is doing is calling the inner function. The outer function doesn’t have any bearing other than operating as a closure for the call (as far as this exercise is concerned).

So, in the case of the scale2d exercise, for example:

function scale2d(outerX, outerY) {
    function scale(innerX, innerY) {
        const scaledCoord = [outerX, outerY];
        scaledCoord[0] *= innerX;
        scaledCoord[1] *= innerY;
        return scaledCoord;
    }
    return scale;
}

const doubleScale = scale2d(2, 2);
const scaledAns = doubleScale(6, -3);

The 2, 2 are just being held in closure; there is nothing else that needs to be done. Additionally the scale function inside is the only thing that is returning, as you said, and so doubleScale can almost be treated as:

const doubleScale = scale(innerX, innerY);

From there, the 6, -3 can be passed into the scale function.

This is where it all began to click.

Taking that a step further, I could now then see that the numbers being held in closure were no different from functions being held in closure.

So from there, I carefully applied that logic using functions instead of numbers and was able to get the outer function returning a composed function!

So my end result looks like this:

export function composeTransform(f, g) {
    function compose(x, y) {
        const composedFunc = f(x, y);
        return g(composedFunc[0], composedFunc[1]);
    }
    return compose;
}

I struggled a bit in wrapping my head around the idea that the result of one function is being used in another function. But I see now that it was because i was focused on trying to get the result to look like f(g(x)) as it showed in the prompt, and even though the end result runs like that, it doesn’t mean the code looks like that. Especially since you are dealing with an array, you need a way to deal with the inner function results appropriately.

I’m sure this sounds very roundabout, and there are better ways to accomplish this, but I’m just happy I was able to figure this out, especially since this was the first exercise I really struggled with out the gate!

Thanks!

Congrats on understanding the problem and solve it!
As for the point of :

But I see now that it was because i was focused on trying to get the result to look like f(g(x)) as it showed in the prompt, and even though the end result runs like that, it doesn’t mean the code looks like that. Especially since you are dealing with an array, you need a way to deal with the inner function results appropriately.

There is a concept in the syllabus called : Array Destructuring , you can take a look at it and then comeback and improve your solution afterward. It is a simple concept that will help doing a lot of middle man assignment.

Congratulations!

Did you mean to say returning instead of calling?

scale2d never itself calls scale. Instead, it only creates and returns it.

For the rest it looks like you have really understood the matter.