Closures
From dis-Emi-A
A closure is essentially a fragment of code with associated data. In the most general sense this could match:
- functions with parameters
- loops with iterators
- inner classes
- normal class object instances
- namespaces with variables
- genuine lambda functions
- callback functions
The list I'm sure keeps going, but abstractly they are all just fragments, or collections, or code with associate data.
Refer to the Wikipedia:Closure (computer science).
Note that this page uses = to assign functions which defines non-overriden functions. Most functions in the language probably won't be done that way, refer to FunctionOverloading.
Contents |
Unification
Rather than introduce a lot of syntax to support all of those cases, as they all have purpose, it would be desirable to have a single unifying syntax. The most natural syntax, and most understood, would likely be that of function notation. Though it may be better to think about closures in terms of classes.
A C style functional view of a simple function:
int NextState( int curState, int incMethod )
{
int nextState = /* something with curState, incMethod*/
return nextState;
}
A C++ class view of the same function:
class State
{
int curState;
int incMethod;
int Next()
{
nextState = /* something with curState, incMethod */
curState = nextState;
return nextState;
}
}
Both pieces of code are accomplishing the same effect. If we translate into a new language like form (as syntax is not yet clear), we can see they actually look even more similar.
Function form
NextState = curState, incMethod => nextState
{
nextState = /* ... */;
};
Class Form
State = class
{
curState;
incMethod;
Next = void => nextState
{
curState = nextState = /* ... */;
}
}
Now these obviously look quite similar because the syntax has already been made to accomodate this form. But basically a class could be seen as a function without parameters or return values. I wonder if we even need the class keyword since without a signature it has to be class-like. We will however need some way of doing constructors...
Note: Assume that void is the technique used to indicate there are no parameters. (Next = => nextState might look too confusing).
Abstract Form
A closure will always have the basic form:
[signature|"class"|"namespace"|program] [body]
The last item "program" is referring to the entirety of the program which encloses all the data and functions into one. It is included here for completeness, and to show that all of these items exist inside one of the other items (preferably without restriction).
An item with a signature in which the returns reference the parameters has a body defined in those returns.
Typically a closure will exist as part of an assignment, in order to use this later. This will usually look like the following:
Name = [closure]
Sum = x, y => z
{
z = x + y;
}
Sum = x, y => x + y;
Adder = class
{
x, y;
Sum = void => x + y;
}
Instantiation
Now that we have the form there are a few basic things we would like to do with them:
- Call it (for functions)
- Instantiate it (for classes)
- Bind it (for partial functions)
- Iterate it (for looping)
//call it q = Sum( 3, 4 ); //instantiate it mod = /* hmm */ q = mod.Sum(); //bind it fivesum = Sum( 5, ? ); q = fivesum( 4 ); // same as Sum( 5, 4 )
For iteration it is a little less simple when using a named item, so consider an anonymous case instead:
q = 0;
[[ i in 1..5 ]]
{
q += i;
};
Note that the closure part is simply what you may wish to call the loop body. To show this abstractly what is happening we'll rearrage the form:
q = 0;
LoopBody = i
{
q += i;
};
[ 1..5 ] LoopBody;
This shows that the function LoopBody has access to the local Q variable and can be used as the body of the loop. This ordering howing is different from function calls, so perhaps we'd like a clearer syntax for that.
Call Syntax
There are a few different types of manners in which a function can be called:
- Evaluation
- Looping
- Folding
- Mapping
Evaluation
Evaluation is the simplist case:
q = Sum( 3, 4 );
Looping
Looping is the case shown above, but here with a new syntax:
LoopBody([ 1..5 ]);
Folding
Folding applies a binary operator to all elements of the set, refer to Wikipedia:Fold (higher-order function).
q = fold( Add, 1..5 );
Or (for using operator symbols)
q = fold( +, 1..5 );
Possible syntax choices:
q = Add(< 1.. 5 >) q = +< 1..5 > q = Add ** 1..5; q = + ** 1.5; q = fold( +, 1..5 ); q = + >> 1..5;
The use of the word fold may be the best option since it is the clearest and works well with native operator symbols. It also allows fold to technically be implemented as part of the standard library and not natively.
Though I would like to stress these should be a native syntax, and thinking of it as a function call is certainly not what it is doing.
Mapping
Mapping applies a function to a set of input data producing a new set of output data. Wikipedia:Map (higher-order function). Here is a possible syntax:
in = /* some set of orderder number pairs ex. ( 3, 4 ), (6, 2 ) ...*/ out = map( Sum, in );
