我试图通过Y-combinator在C中引用函数名来写递归.但是,我无法在以下尝试中找出函数的类型:
#include <iostream> using std::cin; using std::cout; template<class Function> unsigned long factorial1(Function self,unsigned long n) { return n ? n * self(self,n - 1) : 1; } unsigned long factorial(unsigned long n) { return factorial1(factorial1,n); } int main() { unsigned long n; cin >> n; cout << factorial(n) << '\n'; return 0; }
编译器不能推断什么是功能,我也不能.然后我尝试了以下:
#include <iostream> using std::cin; using std::cout; struct Factorial { template<class Function> unsigned long operator()(Function self,unsigned long n) const { return n ? n * self(self,n - 1) : 1; } }; unsigned long factorial(unsigned long n) { return Factorial()(Factorial(),n); } int main() { unsigned long n; cin >> n; cout << factorial(n) << '\n'; return 0; }
这与上面的例子相比,我将工作函数改为可调用对象,这个函数容易被推导为Factorial,导致以下组合器的完整实现:
#include <iostream> using std::cin; using std::cout; struct Factorial { template<class Function> unsigned long operator()(Function self,n - 1) : 1; } }; template<class Function> auto y(Function f) { return [f](auto n) { return f(f,n); }; } int main() { unsigned long n; cin >> n; cout << y(Factorial())(n) << '\n'; return 0; }
问题是,是否可以将struct Factorial重写为一个简单的函数?
解决方法
你这样做稍微有些错误:factorial1的第一个参数应该是具有类型unsigned long(*)(unsigned long)的factorial1的固定点,而不是factorial1本身,因此不需要为自己提供自己的参数:
unsigned long factorial1(unsigned long(*self)(unsigned long),unsigned long n) { return n ? n * self(n - 1) : 1; }
C不允许作为函数指针传递闭包,所以我们必须:
>传递std ::函数或其他一些包装器作为自我.不太有意思的海事组织
>使用模板魔术在编译时生成固定点函数.
第二个选择可以轻松完成:
template<class X,X(*Fn)(X(*)(X),X)> struct Fix { static X Function(X x) { return Fn(Fix<X,Fn>::Function,x); } };
现在,Fix< unsigned long,factorial1> :: Function is a fixed point of factorial1
:
unsigned long factorial(unsigned long n) { return Fix<unsigned long,factorial1>::Function(n); };
请注意,此修复实现仍以名称引用,所以任何实现固定点组合器都不会有类型的系统黑客.