用 C 编写函数式编程有哪些工具?

最近我一直在思考如何用 C (没有 C + +)进行函数式编程。显然,c 是一个工作语言,并不真正支持函数式编程。

是否有任何编译器/语言扩展可以向语言中添加一些函数式编程结构?GCC 提供了 嵌套函数作为语言扩展; 嵌套函数可以从父堆栈框架访问变量,但是距离成熟的闭包还有很长的路要走。

例如,我认为在 C 语言中非常有用的一点是,在任何需要函数指针的地方,都可以传递一个 lambda 表达式,创建一个衰减为函数指针的闭包。C + + 0x 将包含 lambda 表达式(我认为这很棒) ; 然而,我正在寻找适用于直接 C 的工具。

[编辑]澄清一下,我并没有试图用 C 语言解决一个更适合函数式编程的特定问题; 我只是好奇,如果我想这样做的话,会有哪些工具存在。

62016 次浏览

我想到的主要问题是代码生成器的使用。您是否愿意使用提供函数式编程的不同语言编程,然后从中生成 C 代码?

如果这不是一个有吸引力的选择,那么你可以滥用 CPP,以获得一部分的方式。宏系统应该允许您模拟一些函数式编程思想。我听说 gcc 是这样实现的,但我从来没有检查过。

C 语言当然可以使用函数指针来传递函数,主要的问题是缺乏闭包和类型系统会妨碍函数的传递。您可以探索比 CPP (比如 M4)更强大的宏系统。我想最终,我的建议是,真正的 C 不是没有付出巨大努力就能完成任务的,但是您可以扩展 C 来使它能够完成任务。如果您使用 CPP,那么这个扩展看起来最像 C,或者您可以转到另一端,从其他语言生成 C 代码。

很多编程语言都是用 C 语言编写的,其中一些支持一级公民的函数,这方面的语言有 ecl (embbedabble common lisp IIRC) ,Gnu Smalltalk (gst)(Smalltalk 有块) ,然后还有“闭包”的库,例如 glib2 < a href = “ http://library ary.gnome.org/devel/goobject/stability/section-signal.html # close”rel = “ nofollow noReferrer”> http://library.gnome.org/devel/gobject/unstable/chapter-signal.html#closure 至少接近函数式编程。因此,使用其中的一些实现来进行函数式编程可能是一种选择。

或者你可以去学习奥卡姆、哈斯克尔、莫扎特/奥兹或类似的音乐; -)

问候

关于 C 语言,你想让它实现什么功能,语法还是语义?函数式编程的语义当然可以添加到 C 编译器中,但是当您完成这项工作时,您实际上已经拥有了一种现有函数式语言的等价物,例如 Scheme、 Haskell 等等。

只学习那些直接支持这些语义的语言的语法会更好地利用时间。

FFCALL 允许在 C 中构建闭包—— callback = alloc_callback(&function, data)返回一个函数指针,使得 callback(arg1, ...)等效于调用 function(data, arg1, ...)。但是,您必须手动处理垃圾收集。

与此相关的是,积木已经被添加到了苹果的 GCC 分支中; 它们不是函数指针,但是它们可以让你传递 lambdas,同时避免手动构建和释放捕获变量的存储空间(有效地,一些复制和引用计数发生了,隐藏在一些语法糖和运行时库之后)。

如果要实现闭包,就必须熟练使用汇编语言和堆栈交换/管理。我不是反对,只是说你必须这么做。

不知道如何用 C 语言处理匿名函数,不过在冯诺依曼机器上,你可以在高速上执行匿名函数。

不知道 C。Objective-C 中有一些函数式的特性,OSX 上的 GCC 也支持一些特性,但是我还是建议开始使用函数式语言,上面提到了很多。我个人开始与阴谋,有一些优秀的书籍,如小阴谋家,可以帮助你这样做。

你可以使用 GCC 的嵌套函数来模拟 lambda 表达式,事实上,我有一个宏来做这件事:

#define lambda(return_type, function_body) \
({ \
return_type anon_func_name_ function_body \
anon_func_name_; \
})

使用方法如下:

int (*max)(int, int) = lambda (int, (int x, int y) { return x > y ? x : y; });

菲利克斯的语言可以编译成 C + + ,如果你不介意 C + + 的话,这可能是一个基石。

哈特尔和穆勒的书,函数式 C,现在(2012-01-02)可以在: http://eprints.eemcs.utwente.nl/1077/找到(有一个链接到 PDF 版本)。

函数式编程不是关于 lambdas 的,而是关于纯函数的:

  1. 只使用函数参数,不使用全局状态。

  2. 尽量减少副作用,例如 printf 或任何 IO。返回可以执行的描述 IO 的数据,而不是直接在所有函数中造成副作用。

这可以在普通的 C 语言中实现,不需要魔法。

函数式编程风格的先决条件是第一类函数。 如果你接下来能忍受的话,它可以在便携式 C 中进行模拟:

  • 手动管理词法作用域绑定,也就是闭包。
  • 函数变量生命周期的手动管理。
  • 函数应用程序/调用的替代语法。
/*
* with constraints desribed above we could have
* good approximation of FP style in plain C
*/


int increment_int(int x) {
return x + 1;
}


WRAP_PLAIN_FUNCTION_TO_FIRST_CLASS(increment, increment_int);


map(increment, list(number(0), number(1)); // --> list(1, 2)




/* composition of first class function is also possible */


function_t* computation = compose(
increment,
increment,
increment
);


*(int*) call(computation, number(1)) == 4;

此类代码的运行时可以小到下面的一个

struct list_t {
void* head;
struct list_t* tail;
};


struct function_t {
void* (*thunk)(list_t*);
struct list_t* arguments;
}


void* apply(struct function_t* fn, struct list_t* arguments) {
return fn->thunk(concat(fn->arguments, arguments));
}


/* expansion of WRAP_PLAIN_FUNCTION_TO_FIRST_CLASS */
void* increment_thunk(struct list_t* arguments) {
int x_arg = *(int*) arguments->head;
int value = increment_int(x_arg);
int* number = malloc(sizeof *number);


return number ? (*number = value, number) : NULL;
}


struct function_t* increment = &(struct function_t) {
increment_thunk,
NULL
};


/* call(increment, number(1)) expands to */
apply(increment, &(struct list_t) { number(1), NULL });

本质上,我们模仿一类函数,闭包表示为一对函数/参数加一束宏。可以找到完整的代码 给你

我用 C 编写函数式编程的方法是用 C 编写一个函数式语言解释器,我把它命名为 Fexl,它是“函数表达式语言”的缩写

这个解释器非常小,在启用了 -O3的系统上可以编译到68K。它也不是一个玩具-我正在使用它为所有新的生产代码我写我的业务(基于网络的会计投资伙伴关系。)

现在我写 C 代码只是为了(1)添加一个内置函数来调用一个系统例程(例如 fork、 exec、 setrlimit 等) ,或者(2)优化一个本来可以用 Fexl 写的函数(例如搜索子字符串)。

模块机制基于“上下文”的概念。上下文是一个函数(用 Fexl 编写) ,它将一个符号映射到它的定义。读取 Fexl 文件时,可以使用任何上下文解析它。这允许您创建自定义环境,或者在受限制的“沙箱”中运行代码

Http://fexl.com