我试图在C中实现Haskell的折叠函数的一个版本但是已经碰到了一个墙,使它变得通用,因为我想使+或*字符(在foldr中的char)作为补充工作或乘法。我正在考虑尝试一个宏,但不确定什么会起作用。
这里是代码:
HashMap<String, MyModel> myHashMap;
主要问题是让char工作,所以我可以说:
int
foldr(int *v, int (*f)(int*), int x, char y)
{
int temp;
if(*v == (int) NULL) //v is null terminated int array
return x;
else{
temp = *v;
return temp y ((*f)(++v));
}
}
它会起作用。 感谢
答案 0 :(得分:1)
我将展示一种基于递归的方法。作为练习,如果您愿意,可以将其转换为迭代解决方案。
(警告:未经测试)
Haskell中:
foldr :: (Int->Int->Int) -> Int -> [Int] -> Int
foldr f x [] = x -- base case
foldr f x (v:vs) = f v (foldr f x vs) -- recursion
C:
int foldr(int (*f)(int,int),
int x,
int *v, size_t length) {
// base case
if (length == 0) return x;
// recursion
return f(*v, foldr(f, x, v+1, length-1));
}
测试:
int add(int a, int b) {
return a+b;
}
int main() {
int a[] = {1,2,3} ;
int res = foldr(add, 0, a, sizeof a/sizeof *a);
printf("%d\n", res);
return 0;
}
如果您传递上面的正确函数指针(如add
),则无需传递字符运算符'+'
。
请注意,函数式编程语言也允许构建闭包,如:
let y = 5
in foldr (\x c -> x*y+c) 0 [1..3]
注意函数\x c -> x*y+c
如何也取决于y
的值。 C不允许执行工艺闭包,但如果允许C函数添加y
参数,则可以模拟捕获的void *
。
int foldr(int (*f)(void *, int, int),
void *data,
int x,
int *v, size_t length) {
// base case
if (length == 0) return x;
// recursion
return f(data, *v, foldr(f, data, x, v+1, length-1));
}
测试:
int g(void *data, int x, int c) {
int y = *(int *)data;
return x*y+c;
}
int main() {
int a[] = {1,2,3} ;
int y = 5;
int res = foldr(g, &y, 0, a, sizeof a/sizeof *a);
printf("%d\n", res);
return 0;
}
通过这种方式,您可以将g
重复使用y
的不同值。如果需要捕获更多变量,请将指针传递给包含所有此类变量的合适struct
。