Hob*_*lin 17 c functional-programming higher-order-functions
是否有一种"适当的"方式在C中实现更高阶的函数.
我对这里的可移植性和语法正确性等问题非常好奇,如果有多种方法,那么优点和缺点是什么.
编辑:我想知道如何创建更高阶函数的原因是我编写了一个系统来将PyObject列表(在调用python脚本时得到)转换为包含相同数据但以非方式组织的C结构列表依赖于python.h库.所以我的计划是有一个函数,它遍历pythonic列表并在列表中的每个项目上调用一个函数,并将结果放在一个列表中然后返回.
所以这基本上是我的计划:
typedef gpointer (converter_func_type)(PyObject *)
gpointer converter_function(PyObject *obj)
{
// do som stuff and return a struct cast into a gpointer (which is a void *)
}
GList *pylist_to_clist(PyObject *obj, converter_func_type f)
{
GList *some_glist;
for each item in obj
{
some_glist = g_list_append(some_glist, f(item));
}
return some_glist;
}
void some_function_that_executes_a_python_script(void)
{
PyObject *result = python stuff that returns a list;
GList *clist = pylist_to_clist(result, converter_function);
}
Run Code Online (Sandbox Code Playgroud)
并澄清问题:我想知道如何以更安全和更正确的方式做到这一点.我真的想保持更高阶的功能风格,但如果这是不赞成的话,我非常感谢以其他方式做到这一点.
Chu*_*uck 19
从技术上讲,高阶函数只是获取或返回函数的函数.所以像qsort这样的东西已经是高阶的.
如果你的意思更像是在函数式语言中找到的lambda函数(高阶函数真正变得有用的话),那么这些函数要难得多,而且在当前标准C中无法自然完成.它们只是不属于语言.Apple的区块扩展是最佳候选者.它只适用于GCC(和LLVM的C编译器),但它们确实非常有用.希望这样的东西会流行起来.以下是一些相关资源:
在C中实现高阶函数的一个大问题是,要做任何非平凡的事情,你需要闭包,这是一个函数指针,增加了包含他们有权访问的局部变量的数据结构.因为闭包背后的整个想法是捕获局部变量并将它们与函数指针一起传递,所以没有编译器支持就很难做到.即使有编译器支持,如果没有垃圾收集也很难做到,因为变量可能存在于其范围之外,因此很难确定何时释放它们.
在直接的 c 中,这实际上只能通过函数指针来完成,这既是一种痛苦,也不适合这种类型的事情(这也是它们痛苦的部分原因)。不过,块(或闭包,根据非苹果公司的说法)非常适合这一点。他们在 gcc-4.x 或其他东西中编译,然后 icc 一些东西,但不管你在找什么。不幸的是,我似乎无法在网上找到任何好的教程,但可以说它的工作原理如下:
void iterate(char *str, int count, (^block)(str *)){
for(int i = 0; i < count; i++){
block(list[i]);
}
}
main() {
char str[20];
iterate(str, 20, ^(char c){
printf("%c ", c);
});
int accum = 0;
iterate(someList, 20, ^(char c){
accum += c;
iterate(str, 20, ^(char c){
printf("%c ", c);
});
});
}
Run Code Online (Sandbox Code Playgroud)
显然这段代码毫无意义,但它打印字符串 (str) 的每个字符,中间有一个空格,然后将所有字符加在一起到 accum 中,每次执行它都会再次打印出字符列表。
希望这可以帮助。顺便说一下,块在 Mac OS X Snow Leopard api-s 中非常明显,我相信在即将到来的 C++0x 标准中,所以它们并不是那么不寻常。
这是一个问题的答案:如何在 C 中组合函数,这里重定向。
您可以创建数据结构来实现列表数据类型。该结构可以包含函数指针。
#include<stdlib.h>
#include<malloc.h>
typedef (*fun)();
typedef struct funList { fun car; struct funList *cdr;} *funList;
const funList nil = NULL;
int null(funList fs){ return nil==fs; }
fun car(funList fs)
{
if(!null(fs)) return fs->car;
else
{
fprintf(stderr,"error:can't car(nil) line:%d\n",__LINE__);
exit(1);
}
}
funList cdr(funList ls)
{ if(!null(ls)) return ls->cdr;
else
{
fprintf(stderr,"error:can't cdr(nil) line:%d\n",__LINE__);
exit(1);
}
}
funList cons(fun f, funList fs)
{ funList ls;
ls=(funList) malloc(sizeof(struct funList));
if(NULL==ls)
{
fprintf(stderr,"error:can't alloc mem for cons(...) line:%d\n",__LINE__);
exit(1);
}
ls->car=f;
ls->cdr=fs;
return ls;
}
Run Code Online (Sandbox Code Playgroud)
我们可以编写一个应用函数列表的函数 comp:
type_2 comp(funList fs, type_1 x)
{
return (null(fs)) ? x : car(fs)(comp(cdr(fs),x));
}
Run Code Online (Sandbox Code Playgroud)
它是如何工作的一个例子。我们使用 (fgh) 作为 cons(f,cons(g,cons(h,nil))) 的简写,它应用于给定的参数 x:
comp((f g h),x)
Run Code Online (Sandbox Code Playgroud)
=
f(comp((g h),x))
Run Code Online (Sandbox Code Playgroud)
=
f(g(comp((h),x)))
Run Code Online (Sandbox Code Playgroud)
=
f(g(h(comp(nil,x))))
Run Code Online (Sandbox Code Playgroud)
=
f(g(h(x)))
Run Code Online (Sandbox Code Playgroud)
如果您在 SML 或 Haskell 等类型化语言中使用了多态列表类型,则 comp 的类型应该是:
comp :: ([a -> a],a) -> a
Run Code Online (Sandbox Code Playgroud)
因为在这种情况下,列表中的所有成员都具有相同的类型。在这个意义上,C 可以更灵活。也许像
typedef void (*fun)();
Run Code Online (Sandbox Code Playgroud)
或者
typedef (*fun)();
Run Code Online (Sandbox Code Playgroud)
你应该看看 C 手册是怎么说的。并确保所有连续函数都具有兼容的类型。
要组合的函数应该是纯函数,即没有副作用也没有自由变量。
如果您热衷于在普通 C 中执行此操作,您需要记住包括将上下文指针从函子的调用者(高阶函数)传递给传入的函数的选项。这让您可以充分模拟一个可以让事情很容易地工作的闭包。那个指针指向什么......好吧,这取决于你,但它应该是void*函子的API(或它的许多别名之一,例如gpointer在GLib世界或ClientDataTcl C API中)。
[编辑]:使用/调整您的示例:
typedef gpointer (converter_func_type)(gpointer,PyObject *)
gpointer converter_function(gpointer context_ptr,PyObject *obj)
{
int *number_of_calls_ptr = context_ptr;
*number_of_calls_ptr++;
// do som stuff and return a struct cast into a gpointer (which is a void *)
}
GList *pylist_to_clist(PyObject *obj, converter_func_type f, gpointer context_ptr)
{
GList *some_glist;
for each item in obj
{
some_glist = g_list_append(some_glist, f(context_ptr,item));
}
return some_glist;
}
void some_function_that_executes_a_python_script(void)
{
int number_of_calls = 0;
PyObject *result = python stuff that returns a list;
GList *clist = pylist_to_clist(result, converter_function, &number_of_calls);
// Now number_of_calls has how often converter_function was called...
}
Run Code Online (Sandbox Code Playgroud)
这是如何做到这一点的一个简单示例,但它应该向您展示方法。