Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

can a closure contain (or return?) a pure function #46

Open
magopian opened this issue Oct 22, 2013 · 4 comments
Open

can a closure contain (or return?) a pure function #46

magopian opened this issue Oct 22, 2013 · 4 comments

Comments

@magopian
Copy link

I'm wondering if the following question (from the "closures" part: https://leanpub.com/javascript-allonge/read#closures) should read "returns" instead of "contains":

If pure functions can contain closures, can a closure contain a pure function? Using only what we’ve learned so far, attempt to compose a closure that contains a pure function. If you can’t, give your reasoning for why it’s impossible.

My first idea was to come up with this:

function (x) {
  return function(y) {
    return (function(z) {
      return z
    })(y) + x
  }
} 

This one contains a pure function, and could be seen as useful, and the answer could then be "yes".

However, if the sentence is reworded to use "returns", then I believe the answer would then be "no":

If pure functions can contain closures, can a closure contain a pure function? Using only what we’ve learned so far, attempt to compose a closure that RETURNS a pure function. If you can’t, give your reasoning for why it’s impossible.

In this case, here's an example:

function (x) {
  return function (y) {
    return function (z) {
      return z
    }
  }
} 

In this case, the function (z) { return z }, even though it's pure, still is in a closure, and still needs its parent's environment (so, its closure).
You could also argue that this construct is pretty useless, as neither x nor y are used.

On a side note, wouldn't it be beneficial to the reader to have this question reworded to something like "show that a closure can't return a pure function ..."

@kid-icarus
Copy link

👍

@mehranhatami
Copy link

@magopian When you say:

even though it's pure, still is in a closure, and still needs its
parent's environment (so, its closure).

you are making assumptions, based on what you think is a necessary part of these closure statements, a return statement which RETURNS a function. Whereas there is no need to return any of those functions, although it makes more sense in the real world and also in the world of functional programming, but in the world of theoretical JavaScript concepts, you don't need to return the function to have a closure.

To Make it more clear I thought why not make an actual working example, which does the exact same thing without using the return statement.

Before getting into the main part of my example let's say we have a storage to store our functions, say for the sake of creating less pointers to them, although this pattern could have a lot of implications but here we just need it just to help us not create inline variables for our functions:

var FN = (function () {
  var storage = [];

  FN.has = function (id) {
    return (typeof id === 'number' && id > -1 && id < storage.length);
  };

  function FN(fn) {
    if (typeof fn === 'number') {
      return storage[fn];
    } else if (typeof fn === 'function') {
      return (fn.__storeId__ = storage.push(fn) - 1);
    } else {
      console.warn('Invalid input parameter!');
    }
  }

  FN.call = function (id) {
    var fn = storage[id],
      args;
    if (typeof fn === 'function') {
      args = Array.isArray(arguments[1]) ?
        arguments[1] :
        Array.prototype.slice.call(arguments, 1);

      result = fn.apply(undefined, args);

      return {
        result: result,
        call: function () {
          if (typeof result === 'number' && FN.has(result)) {
            return FN.call(result, Array.prototype.slice.call(arguments));
          }
          return null;
        },
        valueOf: function () {
          return result;
        }
      };
    } else {
      console.warn('Invalid input parameter!');
    }
  };

  return FN;
}());

I know the code block above may sound complicated, but let's use it as a black box and assume this allows us just to use closures without returning functions. the first code block I want to mention here is the code example in the book:

var fn = function (x) {
  return function (y) {
    return function (z) {
      return x + y + z;
    }
  }
};

console.log(fn(10)(11)(6) == 27);

As we all know none of these functions is pure except for fn itself.

Using FN api we can transform it to:

var fn = function A(x) {
  var fny,
    fnyId;

  fny = function (y) {
    var fnz = function (z) {
      function () {

      }
      return x + y + z
    };

    //here we store the 'fnz' function in storage
    var fnzId = FN(fnz);

    //here we only return a number not a function
    return fnzId;
  };

  //here we store the 'fny' function in storage
  fnyId = FN(fny);

  //here we only return a number not a function
  return fnyId;
};

//here 'fnId' is only a number not a function
var fnId = FN(fn);

This may seem much more code but I transformed it like this just to put comments, but the better syntax transformation could be:

var fnId = FN(function A(x) {
  return FN(function (y) {
    return FN(function (z) {
      return x + y + z
    });
  });
});

Which is more like the first closure code block we have mentioned above, but with a big difference:

None of these function RETURNS functions.

and the way we could have this nested function call:

console.log(fn(10)(11)(6) == 27);

is like:

console.log(FN.call(fnId, 10).call(11).call(6) == 27);

As you see we get almost the same result using only numbers, without passing functions around.
the idea here is now if you do:

var fnId = FN(function (x) {
  return FN(function (y) {
    return FN(function (z) {
      return z;
    });
  });
});

console.log(FN.call(fnId, 10).call(11).call(6) == 6);

the most inner function which as it is mentioned on the book is:

the I Combinator or Identity Function

is a pure function and if you save its storeId somewhere like:

var mostInnerfnId;

var fnId = FN(function (x) {
  return FN(function (y) {
    return (mostInnerfnId = FN(function (z) {
      return z;
    }));
  });
});

And then if you call right to its upper function:

FN.call(fnId, 10).call(11);

Now you can have access to this function like:

var fn = FN(mostInnerfnId);

which can be called as a pure standalone function:

fn(26);//output: 26

All the code above here is just to clarify one single point. The way closure environment object gets managed doesn't have anything to do with returning functions, it is all about containing or having nested function definitions and pure functions are always pure no matter if you return them or not. Basically when you say:

In this case, the function (z) { return z }, even though it's pure,
still is in a closure, and still needs its parent's environment (so,
its closure).

as it is called in my last code block, it doesn't need its parent's environment object. It only needs to get defined, then you could call it anywhere.

Hope this could be helpful.

@ameensol
Copy link

ameensol commented Dec 2, 2015

@magopian I didn't read the above comment (tl;dr) but just wanted to point out that your example of a closure returning a pure function wasn't correct.

Your example:

function (x) {
  return function (y) {
    return function (z) {
      return z
    }
  }
} 

According to @raganwald the definition of a closure is "a function containing one or more free variables". Since none of the functions above contain any free variables, they are all in fact pure functions, despite being nested.

That said, I think you're right that "contain" should be "return" in the context of the original challenge. A closure can contain a pure function pretty simply.

Consider this closure:

(x) => {
  let foo = (a) => a
  return foo(y * x)
}

I realize this is banal, but the closure above does "contain" the pure function foo.

I can also think of a somewhat contrived example of a closure returning a pure function:

(x) => 
  (y) => {
    return z ? (a) => a : (a) => y * a
  }
}

In this case, the first function (x) => ... is pure but the second (y, z) => ... is a closure which depends on the free variable z and may return the pure function (a) => a if z is truthy but will otherwise return the closure (a) => y * a if z is falsy.

@hectorip
Copy link

So, the conclusion is that it is possible that a closure both contains and returns a pure function?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants