在 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);
}

并澄清问题:我想知道如何在更安全、更正确的 C 中做到这一点。我真的很想保留高阶函数的风格,但如果这是不受欢迎的,我非常感谢以其他方式做到这一点。

有帮助吗?

解决方案

如果你是热衷于用标准C这样做,你需要记住,包括从仿函数(高阶函数)来传递的函数的调用者的上下文指针传递的选项。这让您模拟够封闭,你可以做的事情很容易的工作不够。什么是指针指向......好吧,这是你的,但它应该是仿函数的API(或许多别名它,比如在GLib的世界void*gpointer Tcl的C API中的一个)在ClientData

[编辑]:为了在使用/适应您的示例:

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...
}

这是怎么做的一个简单的例子,但它应该告诉你怎么走。

其他提示

从技术上讲,高阶函数只是接受或返回函数的函数。所以像 qsort 这样的东西已经是高阶的了。

如果你的意思更像是函数式语言中的 lambda 函数(这是高阶函数真正有用的地方),那么这些要困难得多,并且在当前标准 C 中无法自然完成。它们只是不是语言的一部分。苹果的块扩展是最好的选择。它只适用于 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);
    });
  });
}

显然这代码是没有意义的,但它它打印的字符串(STR)与它之间的空间中的每一个字符,然后将所有的字符一起放入ACCUM,每它时它打印出的字符列表试。

希望这有助于。顺便说一句,块是在Mac OS X Snow Leopard的API-S非常明显的,而且我相信在即将到来的C ++ 0x标准,所以他们并不是真正的不寻常。

实际上任何有趣高阶函数应用需要封闭件,其用C需要的手动定义和填充结构函数的参数laborous且容易出错的例行程序。

这是一个问题的答案:如何编写在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;
}

我们可以写一个函数comp施加的函数的列表:

type_2 comp(funList fs, type_1 x)
{  
   return (null(fs)) ? x : car(fs)(comp(cdr(fs),x)); 
}

它是如何工作的例子。我们用(F G H),为短符号用于利弊(F,缺点(克,利弊(H,无))),其被施加到给定自变量x:

comp((f g h),x)

=

f(comp((g h),x))

=

f(g(comp((h),x)))

=

f(g(h(comp(nil,x))))

=

f(g(h(x)))

如果你有像SML或哈斯克尔类型化的语言使用的多态列表类型比较的类型应该是:

comp :: ([a -> a],a) -> a

,因为在这种情况下列表中的所有成员具有相同的类型。 C可在这个意义上更加灵活。可能像

typedef void (*fun)();

typedef (*fun)();

您应该看到关于这个的C语言手册发言权。并确保所有连续函数有兼容的类型。

要撰写的功能应该是纯的,即没有副作用,也没有自由变量。

在直C中很难做到。在 C++ 中更可能(参见 函子教程 或升压的 绑定功能 图书馆)。最后, C++0x 添加了对 lambda 函数的本机支持, ,它负责在闭包中捕获函数所依赖的所有变量。

如果您想要创建更高级的功能,不使用C,有是C解决您的问题。他们可能不优雅,或者他们可能会更优雅,你知道。

[编辑]我建议实现此目标的唯一途径是使用脚本语言。也有人叫我出去就可以了。所以,我替换该建议与此:[/编辑]

什么是你想达到什么目的?如果你想模仿关闭,使用一种语言,支持他们(你可以绑定到红宝石,Lua中的JavaScript等通过库)。如果你想使用回调函数,函数指针确定。函数指针结合C(指针和弱类型系统)最危险的地方,所以要小心。函数指针声明不阅读的乐趣,要么。

您发现使用函数指针,因为他们有一些C库。如果你正在编写一个库,也许你需要使用它们了。如果你只是使用他们自己的代码中,你很可能不会在C.思考你在Lisp或计划或红宝石或思考......并试图把它写在C.了解的C方式。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top