Q:

How can you recover the source code from a pure JavaScript function?

By Pure, I mean in the sense of the λ-calculus, i.e., a single-argument function containing nothing on its body other than single-argument functions and single argument function calls. By recovering the source code, I mean up to variable renaming. So, for example,
n2 = function(v0){return function(v1){return v0(v0(v1))}}
console.log(source(n2));
console.log(source(n2(n2)));

Should print:
function(v0){return function(v0){return v0(v0(v1))}}
function(v0){return function(v0){return v0(v0(v0(v0(v1))))}}

That is, the first line shows the original source of the function n2, and the second one shows the source of the function that is returned by the evaluation of n2(n2). 
I've managed to implement it as follows:
function source(f){
    var nextVarId = 0;
    return (function recur(f){
        if (typeof f === "function"){
            if (f.isVarFunc) return f(null);
            else {
                var varName = "v"+(nextVarId++);
                var varFunc = function rec(res){
                    var varFunc = function(arg){
                        return arg === null
                            ? "("+res.join(")(")+")"
                            : rec(res.concat(recur(arg)));
                    };
                    varFunc.isVarFunc = true;
                    return varFunc;
                };
                varFunc.isVarFunc = true;
                var body = f(varFunc([varName]));
                body     = body.isVarFunc ? body(null) : recur(body);
                return "(function("+varName+"){return "+body+"})";
            };
        } else return f;
    })(f);
};

The issue is that I'm using some rather ugly method of tagging functions by setting their names to a specific value, and that it won't work in functions that are applied more than once (such as a(b)(b)). Is there any better principled way to solve this problem?
Edit: I managed to design a version that seems to be correct in all cases, but it is still an ugly unreadable unprincipled mess.

A:

Finally, this is a considerably cleaned up version of the mess above.
// source :: PureFunction -> String
// Evaluates a pure JavaScript function to normal form and returns the 
// source code of the resulting function as a string.
function source(fn){
    var nextVarId = 0;
    return (function normalize(fn){
        // This is responsible for collecting the argument list of a bound
        // variable. For example, in `function(x){return x(a)(b)(c)}`, it
        // collects `a`, `b`, `c` as the arguments of `x`.  For that, it
        // creates a variadic argumented function that is applied to many
        // arguments, collecting them in a closure, until it is applied to
        // `null`. When it is, it returns the JS source string for the
        // application of the collected argument list.
        function application(argList){
            var app = function(arg){
                return arg === null
                    ? "("+argList.join(")(")+")"
                    : application(argList.concat(normalize(arg)));
            };
            app.isApplication = true;
            return app;
        };
        // If we try to normalize an application, we apply
        // it to `null` to stop the argument-collecting.
        if (fn.isApplication) 
            return fn(null);
        // Otherwise, it is a JavaScript function. We need to create an
        // application for its variable, and call the function on it.
        // We then normalize the resulting body and return the JS
        // source for the function.
        else {
            var varName = "v"+(nextVarId++);
            var body    = normalize(fn(application([varName])));
            return "(function("+varName+"){return "+body+"})";
        };
    })(fn);
};

It is still not perfect but looks much better nether less. It works as expected:
console.log(source(function(a){return function(b){return a(b)}}))

Outputs:
(function(v0){return (function(v1){return (v0)((v1))})})

I wonder how inefficient that is, though.

