| A concrete example: say we use your own. Say we do have a function f(t) that tells us the location of the ball with respect to time. Something like (I'll use JavaScript as my implementation language, as it is capable and accessible): function location_x(t){ return 2 * t; }
function location_y(t){ return 3 * t; }
In calculus, we say that the derivative of f(t) with respect to t can be approximated by calculating the limit as dt approaches 0 in the equation "(f(t + dt) - f(t)) / dt". Since you imply you know linear calculus, I'll not explain the jargon there.Well, f(t) could be anything in that description, it doesn't necessarily have to be a function describing the position of a ball. So why don't we make f a variable? Why don't we write a general-purpose derivation function that can compute the derivative of any function given to it? To do this, we need the ability to treat functions as "first-class citizens", as things we can manipulate just as much as we do primitive integers and decimal numbers. That includes being able to refer to a function without evaluating it (i.e. storing it as a variable, able to pass it around, with no special knowledge of its purpose, just as we can pass integers to a function and it doesn't matter that the integer is 10 or 173 or -83491, we pass it to our function in the same way every time). We also need to be able to create functions on the fly (just as we might create integers other than the ones we typed in literally through arithmetic operations). We finally need the ability to capture the the values of any variable defined outside of our functions at the time the function was defined. This is called lexical scope, because it follows how we read the code, and functions that do this are called closures, because they "close over" the referenced values. Imagine the function hugging out further and further to accept everyone in. It's important that the values get captured and not the references, which we'll see why later. Because of these three things, I could have also written my location functions as: var location_x = function (t){ return 2 * t; }
var location_y = function (t){ return 3 * t; }
How do you write the literal value of an integer? "2". How do you write the literal value of a function? In JavaScript it's "function(args){statements}". A named function--as you are used to them in procedural languages--is really just a function value stored in a variable that has a name. Just like a named integer is just a literal integer stored in a variable that has a name. We could even have an array of functions! var location = [function (t){ return 2 * t; },
function (t){ return 3 * t; }];
Okay, so what does our derive function look like: function derive(f){ // f is an argument that accepts a function as a parameter
return function(t, dt){ // we will return a new function
return (f(t + dt) - f(t)) / dt; // the bare definition of a derivative! Nothing fancy!
};
}
This is where "closing over" gets important. I want the function(t, dt)... to have access to the value of f when it was created. A simpler example, say I wanted to make an array of functions: var arr = [];
for(var i = 0; i < 100; ++i)
arr.push(function(t){ return i * t; });
What do you expect arr[50](3) to return? If you said "150", you've been paying attention. Closing over the value of "i" allows us to do natural things with our code.Unfortunately, it's incorrect. JavaScript does unexpected things with scope, so it can break our natural understanding of it. Every one of these 100 functions will return 100 * t, because 100 was the final value of i that caused the for loop to break, and the i variable is still in scope after the for loop finishes. It's one of the ways in which JavaScript is fundamentally broken. In JavaScript, this example has to be fudged to work right: var arr = [];
for(var i = 0; i < 100; ++i)
arr.push((function(_i){ // an anonymous function...
return function(t){ return _i * t; }
})(i)); // ...that we call right away
We are used to the for loop introducing new scope, but in JavaScript it does not. We have to explicitly introduce the scope. It's bad, but thankfully the ability to treat functions as first-class values allows us to fix it!Moving on, let's apply our derive function: var velocity_x = derive(location_x);
var velocity_y = derive(location_y);
// evaluate a few values
var x = location_x(10); // x == 20
var dx = velocity_x(10, 0.0000001); // 1.999999987845058 which, for an approximation, is very close to the correct value of 2
"Oh, but 2 times t is easy to derive." You might say. Well, what if our location function described the ball moving in an ellipse? location_x = function (t){ return 2 * Math.cos(t); }
location_y = function (t){ return 3 * Math.sin(t); }
Then the derivative is exactly the same: velocity_x = derive(location_x);
velocity_y = derive(location_y);
And we will get reasonably good approximations for increasingly small values of dt.Now, try doing that in C. We live in blessed times where most of the popular languages have the basic building blocks of functional programming enough to support the lambda calculus. This didn't used to be the case. |
Is your claim that functional programming is the lambda calculus? Is dependent on the lambda calculus? Is an implementation of the lambda calculus? Something else?
You seem to have some implicit assumptions or claims here. Stating them explicitly could let the GP know what it is that you think you're demonstrating.