function types上的Wikipedia文章列出了“高阶函数组合函数”的有趣声明:
int (*compose(int (*f)(int), int (*g)(int)))(int);
作为一项学习练习,我想在测试程序中实现此目标,但是失败了,编译器抛出了许多警告和错误。我的尝试:
int a(int x) {
return x + 1;
}
int b(int x) {
return x * 2;
}
int (*compose(int (*f)(int y), int (*g)(int z)))(int x) {
return (*f)(x) - (*g)(x);
}
int main(void) {
int x = 5;
int r = (*compose)((*a)(x), (*b)(x))(x);
printf("Compose result for x = %d: %d\n", x, r);
return 0;
}
我很高兴能解释一下维基百科的声明与f(g(h(x)))
之类的简单函数组成有何不同,以及如何实现,最好是使用类似于我的简单程序。
答案 0 :(得分:4)
这里有几个问题要解决。
compose
选择的签名,您将无法获得所需的运行时合成。如果compose
将返回一个(指向a的)函数-它只能返回一个预先存在的函数。 (*)尝试对您的代码进行此修改:
#include <stdio.h>
int a(int x) {
return x + 1;
}
int b(int x) {
return x * 2;
}
int compose(int (*f)(int y), int (*g)(int z), int x) {
return f(x) - g(x);
}
int main(void) {
int x = 5;
int r = compose(a, b, x);
printf("Compose result for x = %d: %d\n", x, r);
return 0;
}
此compiles。
(*)-理论上,您可以执行运行时编译,并返回指向所得机器代码地址的链接,但这不是语言工具。实际上这是无关紧要的
答案 1 :(得分:2)
您的compose
函数被声明为返回函数指针,但计算并返回一个int
值。
也(*a)(x)
调用a
函数,并将int
结果传递给compose
,而不是指向函数a
本身的指针。与b
相同。
要解决您的问题,首先应使用指向函数compose
和a
的指针调用b
:
int r = (*compose(&a, &b))(x);
然后,您需要使compose
返回指向函数的指针,其中包括创建要返回的函数:
int (*f1)(int);
int (*f2)(int);
int compose_helper(int x)
{
return f1(x) - f2(x);
}
int (*compose(int (*f1_)(int), int (*f2_)(int)))(int)
{
f1 = f1_;
f2 = f2_;
return &compose_helper;
}
在C语言中,实际上没有很好的方法,因为函数组合不能在运行时完成,并且需要有全局状态。
作为一个旁注,我真的建议您为功能指针创建类型别名,以使其更易于阅读和理解。
如
typedef int (fp_type)(int);
fp_type *f1;
fp_type *f2;
fp_type *compose(fp_type *f1_, fp_type *f2_) { ... }
答案 2 :(得分:1)
在C中,您无法在运行时创建新函数; compose
只能返回预定义的函数。这是此类功能的简短示例:
int null(int x) { return 0; }
int f1(int x) { return x*x; }
int f2(int x) { return 2*x; }
int sub_f2_f1 ( int x ) { return f2(x)-f1(x); }
int sub_f1_f2 ( int x ) { return f1(x)-f2(x); }
/*...*/
int (*compose(int (*f)(int), int (*g)(int)))(int)
{
if (f1==f2) return null;
if (f2==null) return f1;
if (f==f2 && g==f1) return sub_f2_f1;
if (f==f1 && g==f2) return sub_f1_f2;
/*...*/
return 0;
}