Geht so etwas überhaupt?
Ein Element sind die Funktionspointer. Es ist immer recht schwierig, die Signatur davon richtig zu treffen, aber ein typedef hilft.
Die nächste Schwierigkeit ist, dass C normalerweise keine inneren Funktionen erlaubt und dass man auch keinen Kontext einbinden kann.
Das lässt sich lösen:
Die Funktion hat einen weiteren Parameter für ein Context-Struct, in dem die Variablen eingebunden werden.
struct closure;
typedef int (*fun_type)(const struct closure *context, const int param);
Das sieht so aus, dass dort die Variable(n) und ein Funktionspointer enthalten sind:
struct closure {
int x;
fun_type fun;
};
Nun muss man die Funktionen ja in für Closures gemachten Programmiersprachen trotzem noch hinschreiben, aber anonym und am richtigen Ort.
In C muss man alle möglichen Funktionen regulär, aber mit der fun_type-Signatur von oben definieren. Die Referenzen auf die eingebundenen Variablen müsse vom context-Parameter kommen, statt implizit verfügbar zu bleiben, z.B.:
int f(const struct closure *context, const int param) {
return (context->x) + param;
}
Die Funktion 2. Ordnung, die die Closure zurückgibt, kann man nun auch definieren, man muss nur die C-Schreibweise akzeptieren und statt die Funktion an Ort und Stelle zu definieren eine der vorher definierten Funktionen referenzieren. Auch das ist äquivalent zu Closures:
struct closure *adder(int x) {
struct closure *result = malloc(sizeof(struct closure));
result->x = x;
result->fun = f;
return result;
}
Und so kann man das ganze dann verwenden:
int main(int argc, char *argv[]) {
int retcode;
if (argc < 2) {
usage(argv[0], "not enough parameters");
}
int x = atoi(argv[1]);
int y = atoi(argv[2]);
struct closure *cl = adder(x);
int i;
for (i = 0; i < y; i++) {
printf("cl(%d)=%d\n", i, cl->fun(cl, i));
}
}
Das komplette Beispiel ist auf github.
In Scala sieht das natürlich viel kürzer aus:
object Closure {
def main(args : Array[String]) : Unit = {
val x : Int = args(0).toInt
val y : Int = args(1).toInt
val f : ((Int) => Int) = adder(x);
val arr = (1 to y).map(f)
println(arr.toString)
}
def adder(x : Int) : ((Int) => Int) = {
(y => x+y)
}
}
Auch das ist auf Github
Schreibe einen Kommentar