【发布时间】:2014-10-23 15:37:04
【问题描述】:
我已经用 Clojure(一种函数式语言)编程有一段时间了,我必须使用 C++ 来上课。我一直在尝试使用我在 Clojure 中喜欢的一些功能(例如,高阶函数、lambda、参数线程、动态类型等),但我遇到了一些难题。
首先,我实现了一个函数get,它接受两个参数:
- 一个集合(向量、列表、哈希映射等),以及
- 索引
并返回该索引处的元素。
我还实现了一个函数conj,它接受两个参数:
- 集合(向量、列表、队列等),以及
- 一个元素/对象(无论集合是什么类型)
并返回添加了元素的集合。在向量的情况下,这与push_back 基本相同。
现在,我希望能够使用如下高阶函数“转发”或“线程化”参数:
using std::vector;
vector<double> my_vec;
forward(my_vec, // take "my_vec"
conj(0.1), // "push" the value of 0.1 to the back of "my_vec"
get(0), // retrieve the first value
inc); // increment that value
它与inc(get(conj(my_vec, 0.1), 0); 相同,但更具可读性(!)。
forward 在这种情况下的返回值应该是 1.1。
为了使forward 函数工作,初始参数之后的参数必须都是高阶函数。也就是说,它们需要类似于以下工作:
template<typename Func>
Func get(int i){
return [i](vector<boost::any> coll)
-> boost::optional<boost::any> {
return get(coll, i);
};
}
但是,编译器无法推断要返回的 lambda 函数的类型。此外,我的猜测是,基于我对boost::any 的极其有限的经验,它无法将vector<double> 转换为vector<boost::any>,尽管boost::any 明显声称它可以充当替代品几乎适用于任何类型。
我希望get 函数具有通用性,因此我不想使用boost::function<double (vector <double>, int)> 或任何类似的特定类型。
另外,如果从get 请求的索引超出范围,我将使用boost::optional 而不是vector 返回null_ptr。
就目前而言,这是我的 forward 函数的外观:
template <typename T1>
optional<T1> forward (T1 expr1){
return expr1;
}
template <typename T1, typename T2>
optional<T1> forward (T1 expr1, T2 expr2){
return forward(expr2(expr1));
}
template <typename T1, typename T2, typename T3>
optional<T1> forward (T1 expr1, T2 expr2, T3 expr3){
return forward(expr2(expr1), expr3);
}
等等。 ...
关于如何让这个forward 函数工作的任何想法?
我也很确定有一种比像我一样进行 arity-overloading 更有效的方法来实现它。
【问题讨论】:
-
查找一元函数和延续器,一个函数式编程概念。 See how it is implemented in C++11.
-
什么编译器和版本?
标签: c++ functional-programming