Lassen Sie uns zunächst auf eine mögliche Python-Implementierung einen Blick.
def f(x, y=None):
if y is None:
return lambda y: f(x, y)
return 'result'
Das einzige, was hier in C getan werden muss, ist irgendwie die lambda
Funktion zu schaffen. Hier wissen wir nicht, dass die PyCFunction die C-Funktion selbst aufruft. Also müssen wir Wrapper darum schreiben und ein neues PyCFunction
Objekt erstellen.
static PyObject* curried (PyObject *old_args, PyObject *new_args);
static PyMethodDef curried_def = {"curried", curried, METH_VARARGS, "curried"};
static PyObject* f (PyObject *self, PyObject *args) {
PyObject *x = NULL, *y = NULL;
if(!PyArg_ParseTuple(args, "O|O", &x, &y))
return NULL;
// validate x
if (y == NULL)
return Py_INCREF(args), PyCFunction_New(&curried_def, args);
// validate y
// do something to obtain the result
return result;
}
static PyObject* curried (PyObject *old_args, PyObject *new_args) {
Py_ssize_t old_args_count = PyTuple_Size(old_args);
Py_ssize_t new_args_count = PyTuple_Size(new_args);
PyObject *all_args = PyTuple_New(old_args_count + new_args_count);
Py_ssize_t i;
PyObject *o;
for (i = 0; i < old_args_count; i++) {
o = PyTuple_GET_ITEM(old_args, i);
Py_INCREF(o);
PyTuple_SET_ITEM(all_args, i, o);
}
for (i = 0; i < new_args_count; i++) {
o = PyTuple_GET_ITEM(new_args, i);
Py_INCREF(o);
PyTuple_SET_ITEM(all_args, old_args_count + i, o);
}
return f(NULL, all_args);
}
dieser die gewünschte Semantik von
f(a, b) -> result
f(a) -> <built-in method curried of tuple object at 0x123456>
f(a)(b) -> result
Hier ergibt mißbrauchen wir die PyCFunction
Art ein wenig und den zweiten Parameter zu PyCFunction_New(&curried_def, args)
geben soll das self
Objekt sein, diese Funktion gebunden, wir daher Ich werde eine eingebaute Methode curried von Tuple-Objekt bekommen. Wenn Sie den Parameter self
der ursprünglichen Funktion benötigen oder Schlüsselwortargumente verwenden, müssen Sie diesen Hack etwas erweitern und ein benutzerdefiniertes Objekt erstellen, das anstelle der args
übergeben wird. Es ist auch möglich, einen Typ wie PyCFunction
für Curry-Funktionen zu erstellen. Soweit ich weiß, gibt es so etwas noch nicht.