在C语言中有什么函数式编程工具?

时间:2021-12-26 20:07:29

I've been thinking a lot lately about how to go about doing functional programming in C (not C++). Obviously, C is a procedural language and doesn't really support functional programming natively.

最近我一直在思考如何在C(而不是c++)中进行函数式编程。显然,C语言是一种过程性语言,它本身并不真正支持函数式编程。

Are there any compiler/language extensions that add some functional programming constructs to the language? GCC provides nested functions as a language extension; nested functions can access variables from the parent stack frame, but this is still a long way away from mature closures.

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

For example, one thing that I think could be really useful in C is that anywhere where a function pointer is expected, you could be able to pass a lambda expression, creating a closure which decays into a function pointer. C++0x is going to include lambda expressions (which I think is awesome); however, I'm looking for tools applicable to straight C.

例如,我认为在C中有一件事非常有用,那就是在任何需要函数指针的地方,你都可以传递一个lambda表达式,创建一个闭包,它会衰减成函数指针。c++ 0x将包含lambda表达式(我觉得这个表达式很棒);但是,我正在寻找适用于直接C的工具。

[Edit] To clarify, I'm not trying to solve a particular problem in C that would be more suited to functional programming; I'm merely curious about what tools are out there if I wanted to do so.

[编辑]澄清一下,我并不是要解决C语言中更适合函数式编程的一个特定问题;我只是好奇如果我想这么做的话,会有什么工具。

13 个解决方案

#1


38  

FFCALL lets you build closures in C -- callback = alloc_callback(&function, data) returns a function pointer such that callback(arg1, ...) is equivalent to calling function(data, arg1, ...). You will have to handle garbage collection manually, though.

FFCALL允许您在C - callback = alloc_callback(&function, data)中构建闭包,它返回一个函数指针,以便回调(arg1,…)等同于调用函数(data, arg1,…)。不过,您必须手动处理垃圾收集。

Relatedly, blocks have been added to Apple's fork of GCC; they're not function pointers, but they let you pass around lambdas while avoiding the need to build and free storage for captured variables by hand (effectively, some copying and reference counting happens, hidden behind some syntactic sugar and runtime libraries).

后来,在苹果的“海湾合作委员会”(GCC)的分支中加入了一些区块;它们不是函数指针,但是它们允许您传递lambdas,同时避免为捕获的变量手工构建和*存储(有效地,一些复制和引用计数发生了,隐藏在一些语法糖和运行时库之后)。

#2


79  

You can use GCC's nested functions to simulate lambda expressions, in fact, I have a macro to do it for me:

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

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

Use like this:

使用这样的:

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

#3


44  

Functional programming is not about lambdas, it is all about pure functions. So the following broadly promote functional style:

函数式编程不是关于lambdas的,它是关于纯函数的。因此,以下几点广泛推广功能性风格:

  1. Only use function arguments, do not use global state.

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

  2. Minimise side effects i.e. printf, or any IO. Return data describing IO which can be executed instead of causing the side effects directly in all functions.

    尽量减少副作用,如打印输出或任何IO。返回描述IO的数据,该数据可以在所有函数中执行,而不会直接导致副作用。

This can be achieved in plain c, no need for magic.

这可以通过简单的c实现,不需要魔法。

#4


17  

Hartel & Muller's book, Functional C, can nowadays (2012-01-02) be found at: http://eprints.eemcs.utwente.nl/1077/ (there is a link to PDF version).

Hartel & Muller的书《函数C》(Functional C)如今(2012-01-02)可以在http://eprints.eemcs.utwente找到。nl/1077/(有PDF版本的链接)。

#5


5  

The main thing that comes to mind is the use of code generators. Would you be willing to program in a different language that provided the functional programming and then generate the C code from that?

我首先想到的是代码生成器的使用。您是否愿意使用提供函数式编程的另一种语言进行编程,然后从中生成C代码?

If that's not an attractive option, then you could abuse CPP to get part of the way there. The macro system should let you emulate some functional programming ideas. I've heard tell that gcc is implemented this way but I've never checked.

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

C can of course pass functions around using function pointers, the main problems are lack of closures and the type system tends to get in the way. You could explore more powerful macro systems than CPP such as M4. I guess ultimately, what I'm suggesting is that true C isn't up to the task without great effort but you could extend C to make it be up to the task. That extension would look the most like C if you use CPP or you could go to the other end of the spectrum and generate C code from some other language.

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

#6


5  

If you want to implement closures, you'll have to get groady with assembly language and stack swapping/management. Not recommending against it, just saying that's what you'll have to do.

如果您想要实现闭包,您将不得不使用汇编语言和堆栈交换/管理。不要反对它,只说那是你必须做的。

Not sure how you'll handle anonymous functions in C. On a von Neumann machine, you could do anonymous functions in asm, though.

不确定如何在c中处理匿名函数。在冯·诺依曼机器上,你可以在asm中处理匿名函数。

#7


4  

Look at Hartel & Muller's book, Functional C

看看Hartel & Muller的书,Functional C

http://www.ub.utwente.nl/webdocs/ctit/1/00000084.pdf
http://www.cs.bris.ac.uk/~henkm/f2c/index.html

http://www.ub.utwente.nl/webdocs/ctit/1/00000084.pdf http://www.cs.bris.ac.uk/ henkm / f2c / index . html

#8


2  

Prerequisite for functional programming style is a first class function. It could be simulated in portable C if you tolerate next:

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

  • manual management of lexical scope bindings, aka closures.
  • 手动管理词汇范围绑定,即闭包。
  • manual management of function variables lifetime.
  • 手动管理函数变量的生命周期。
  • alternative syntax of function application/call.
  • 函数应用/调用的替代语法。
/* 
 * 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;

runtime for such code could be as small as one below

这类代码的运行时可能只有下面的代码那么小

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

In essence we imitate first class function with closures represented as pair of function/arguments plus bunch of macroses. Complete code could be found here.

本质上,我们模仿的是第一个类函数,闭包表示为一对函数/参数加上一串宏。完整的代码可以在这里找到。

#9


1  

Well quite a few programming languages are written in C. And some of them support functions as first class citizens, languages in that area are ecl (embbedabble common lisp IIRC), Gnu Smalltalk (gst) (Smalltalk has blocks), then there are libraries for "closures" e.g in glib2 http://library.gnome.org/devel/gobject/unstable/chapter-signal.html#closure which at least got near functional programming. So maybe using some of those implementations to do functional programming may be an option.

很多编程语言都是用c语言编写的,其中一些语言支持作为一等公民的功能,该领域的语言有ecl (embbedabble common lisp IIRC)、Gnu Smalltalk (gst) (Smalltalk有块),还有用于“闭包”e的库。gglib2中的http://library.gnome.org/devel/gobt/unstable/chapter -signal.html#闭包,至少接近函数式编程。因此,也许使用这些实现来进行函数式编程是一种选择。

Well or you can go learning Ocaml, Haskell, Mozart/Oz or the like ;-)

或者你可以去学习Ocaml, Haskell, Mozart/Oz之类的;

Regards

问候

#10


0  

The Felix language compiles to C++. Maybe that could be a step stone, if you don't mind C++.

Felix语言编译为c++。如果你不介意c++的话,这可能是一个跳板。

#11


0  

The way I went about doing functional programming in C was to write a functional language interpreter in C. I named it Fexl, which is short for "Function EXpression Language."

我在C语言中进行函数式编程的方法是在C中编写一个函数式语言解释器,我将其命名为Fexl,它是“函数表达式语言”的缩写。

The interpreter is very small, compiling down to 68K on my system with -O3 enabled. It's not a toy either - I'm using it for all the new production code I write for my business (web-based accounting for investment partnerships.)

解释器非常小,在启用了-O3的系统上编译到68K。它也不是一个玩具——我把它用在我为公司编写的所有新产品代码中(基于web的投资伙伴关系会计)。

Now I write C code only to (1) add a built-in function that calls a system routine (e.g. fork, exec, setrlimit, etc.), or (2) optimize a function that could otherwise be written in Fexl (e.g. search for a substring).

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

The module mechanism is based on the concept of a "context". A context is a function (written in Fexl) which maps a symbol to its definition. When you read a Fexl file, you can resolve it with any context you like. This allows you to create custom environments, or run code in a restricted "sandbox."

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

http://fexl.com

http://fexl.com

#12


-4  

Dont Know about C. There are some functional features in Objective-C though, GCC on the OSX also supports some features, however I would again recommend to start using a functional language, there are plenty mentioned above. I personally started off with scheme, there are some excellent books such as The Little Schemer that can help you do so.

虽然Objective-C中有一些功能特性,但是OSX上的GCC也支持一些特性,但是我再次建议开始使用函数语言,上面已经提到了很多。我从计划开始,有一些很棒的书,比如小阴谋家可以帮助你这样做。

#13


-6  

What is it about C that you want to make functional, the syntax or the semantics? The semantics of functional programming could certainly be added to the C compiler, but by the time you were done, you'd essentially have the equivalent of one of the existing functional languages, such as Scheme, Haskell, etc.

你想要实现什么功能,语法还是语义?函数编程的语义当然可以添加到C编译器中,但是当您完成这些工作时,您基本上就拥有了与现有函数语言之一相同的功能语言,例如Scheme、Haskell等。

It would be a better use of time to just learn the syntax of those languages which directly support those semantics.

学习直接支持这些语义的语言的语法将是更好的利用时间。

#1


38  

FFCALL lets you build closures in C -- callback = alloc_callback(&function, data) returns a function pointer such that callback(arg1, ...) is equivalent to calling function(data, arg1, ...). You will have to handle garbage collection manually, though.

FFCALL允许您在C - callback = alloc_callback(&function, data)中构建闭包,它返回一个函数指针,以便回调(arg1,…)等同于调用函数(data, arg1,…)。不过,您必须手动处理垃圾收集。

Relatedly, blocks have been added to Apple's fork of GCC; they're not function pointers, but they let you pass around lambdas while avoiding the need to build and free storage for captured variables by hand (effectively, some copying and reference counting happens, hidden behind some syntactic sugar and runtime libraries).

后来,在苹果的“海湾合作委员会”(GCC)的分支中加入了一些区块;它们不是函数指针,但是它们允许您传递lambdas,同时避免为捕获的变量手工构建和*存储(有效地,一些复制和引用计数发生了,隐藏在一些语法糖和运行时库之后)。

#2


79  

You can use GCC's nested functions to simulate lambda expressions, in fact, I have a macro to do it for me:

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

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

Use like this:

使用这样的:

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

#3


44  

Functional programming is not about lambdas, it is all about pure functions. So the following broadly promote functional style:

函数式编程不是关于lambdas的,它是关于纯函数的。因此,以下几点广泛推广功能性风格:

  1. Only use function arguments, do not use global state.

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

  2. Minimise side effects i.e. printf, or any IO. Return data describing IO which can be executed instead of causing the side effects directly in all functions.

    尽量减少副作用,如打印输出或任何IO。返回描述IO的数据,该数据可以在所有函数中执行,而不会直接导致副作用。

This can be achieved in plain c, no need for magic.

这可以通过简单的c实现,不需要魔法。

#4


17  

Hartel & Muller's book, Functional C, can nowadays (2012-01-02) be found at: http://eprints.eemcs.utwente.nl/1077/ (there is a link to PDF version).

Hartel & Muller的书《函数C》(Functional C)如今(2012-01-02)可以在http://eprints.eemcs.utwente找到。nl/1077/(有PDF版本的链接)。

#5


5  

The main thing that comes to mind is the use of code generators. Would you be willing to program in a different language that provided the functional programming and then generate the C code from that?

我首先想到的是代码生成器的使用。您是否愿意使用提供函数式编程的另一种语言进行编程,然后从中生成C代码?

If that's not an attractive option, then you could abuse CPP to get part of the way there. The macro system should let you emulate some functional programming ideas. I've heard tell that gcc is implemented this way but I've never checked.

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

C can of course pass functions around using function pointers, the main problems are lack of closures and the type system tends to get in the way. You could explore more powerful macro systems than CPP such as M4. I guess ultimately, what I'm suggesting is that true C isn't up to the task without great effort but you could extend C to make it be up to the task. That extension would look the most like C if you use CPP or you could go to the other end of the spectrum and generate C code from some other language.

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

#6


5  

If you want to implement closures, you'll have to get groady with assembly language and stack swapping/management. Not recommending against it, just saying that's what you'll have to do.

如果您想要实现闭包,您将不得不使用汇编语言和堆栈交换/管理。不要反对它,只说那是你必须做的。

Not sure how you'll handle anonymous functions in C. On a von Neumann machine, you could do anonymous functions in asm, though.

不确定如何在c中处理匿名函数。在冯·诺依曼机器上,你可以在asm中处理匿名函数。

#7


4  

Look at Hartel & Muller's book, Functional C

看看Hartel & Muller的书,Functional C

http://www.ub.utwente.nl/webdocs/ctit/1/00000084.pdf
http://www.cs.bris.ac.uk/~henkm/f2c/index.html

http://www.ub.utwente.nl/webdocs/ctit/1/00000084.pdf http://www.cs.bris.ac.uk/ henkm / f2c / index . html

#8


2  

Prerequisite for functional programming style is a first class function. It could be simulated in portable C if you tolerate next:

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

  • manual management of lexical scope bindings, aka closures.
  • 手动管理词汇范围绑定,即闭包。
  • manual management of function variables lifetime.
  • 手动管理函数变量的生命周期。
  • alternative syntax of function application/call.
  • 函数应用/调用的替代语法。
/* 
 * 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;

runtime for such code could be as small as one below

这类代码的运行时可能只有下面的代码那么小

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

In essence we imitate first class function with closures represented as pair of function/arguments plus bunch of macroses. Complete code could be found here.

本质上,我们模仿的是第一个类函数,闭包表示为一对函数/参数加上一串宏。完整的代码可以在这里找到。

#9


1  

Well quite a few programming languages are written in C. And some of them support functions as first class citizens, languages in that area are ecl (embbedabble common lisp IIRC), Gnu Smalltalk (gst) (Smalltalk has blocks), then there are libraries for "closures" e.g in glib2 http://library.gnome.org/devel/gobject/unstable/chapter-signal.html#closure which at least got near functional programming. So maybe using some of those implementations to do functional programming may be an option.

很多编程语言都是用c语言编写的,其中一些语言支持作为一等公民的功能,该领域的语言有ecl (embbedabble common lisp IIRC)、Gnu Smalltalk (gst) (Smalltalk有块),还有用于“闭包”e的库。gglib2中的http://library.gnome.org/devel/gobt/unstable/chapter -signal.html#闭包,至少接近函数式编程。因此,也许使用这些实现来进行函数式编程是一种选择。

Well or you can go learning Ocaml, Haskell, Mozart/Oz or the like ;-)

或者你可以去学习Ocaml, Haskell, Mozart/Oz之类的;

Regards

问候

#10


0  

The Felix language compiles to C++. Maybe that could be a step stone, if you don't mind C++.

Felix语言编译为c++。如果你不介意c++的话,这可能是一个跳板。

#11


0  

The way I went about doing functional programming in C was to write a functional language interpreter in C. I named it Fexl, which is short for "Function EXpression Language."

我在C语言中进行函数式编程的方法是在C中编写一个函数式语言解释器,我将其命名为Fexl,它是“函数表达式语言”的缩写。

The interpreter is very small, compiling down to 68K on my system with -O3 enabled. It's not a toy either - I'm using it for all the new production code I write for my business (web-based accounting for investment partnerships.)

解释器非常小,在启用了-O3的系统上编译到68K。它也不是一个玩具——我把它用在我为公司编写的所有新产品代码中(基于web的投资伙伴关系会计)。

Now I write C code only to (1) add a built-in function that calls a system routine (e.g. fork, exec, setrlimit, etc.), or (2) optimize a function that could otherwise be written in Fexl (e.g. search for a substring).

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

The module mechanism is based on the concept of a "context". A context is a function (written in Fexl) which maps a symbol to its definition. When you read a Fexl file, you can resolve it with any context you like. This allows you to create custom environments, or run code in a restricted "sandbox."

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

http://fexl.com

http://fexl.com

#12


-4  

Dont Know about C. There are some functional features in Objective-C though, GCC on the OSX also supports some features, however I would again recommend to start using a functional language, there are plenty mentioned above. I personally started off with scheme, there are some excellent books such as The Little Schemer that can help you do so.

虽然Objective-C中有一些功能特性,但是OSX上的GCC也支持一些特性,但是我再次建议开始使用函数语言,上面已经提到了很多。我从计划开始,有一些很棒的书,比如小阴谋家可以帮助你这样做。

#13


-6  

What is it about C that you want to make functional, the syntax or the semantics? The semantics of functional programming could certainly be added to the C compiler, but by the time you were done, you'd essentially have the equivalent of one of the existing functional languages, such as Scheme, Haskell, etc.

你想要实现什么功能,语法还是语义?函数编程的语义当然可以添加到C编译器中,但是当您完成这些工作时,您基本上就拥有了与现有函数语言之一相同的功能语言,例如Scheme、Haskell等。

It would be a better use of time to just learn the syntax of those languages which directly support those semantics.

学习直接支持这些语义的语言的语法将是更好的利用时间。