假设我有一个applicative
的幼稚实现,这是我出于理智选择的名称,并不是我对其他语言的Applicative
类型类一无所知。实现方法如下:
#include <iostream>
#include <string>
template <typename T>
struct applicative {
template <typename Fn>
auto then(Fn f) const {
return applicative<decltype(f(data_))>{f(data_)};
}
template <typename Fn>
auto and_last(Fn f) const {
return f(data_);
}
T data_;
};
int main() {
applicative<std::string>{"hello world"}
.then([](std::string const& s) {return s.size() * 4; })
.then([](int k) {return k - 2; })
.and_last([](int k) { std::cout << k << "\n"; });
}
现在,可以在许多方面进行改进。提供make_applicative
之类的东西用于就地构建,尝试消除多余的副本和移动(如果有的话)。但是从我看到我们用C ++编写函数的能力开始,我觉得有可能做得更好。任何撰写实现都可以使用,因此让我们在这个codereview.stackexchange问题中选择一个。有了它,我们可以说
auto f1 = [](std::pair<double,double> p) {return p.first + p.second; };
auto f2 = [](double x) {return std::make_pair(x, x + 1.0); };
auto f3 = [](double x, double y) {return x*y; };
auto g = compose(f1, f2, f3);
std::cout << g(2.0, 3.0) << std::endl; //prints '13', evaluated as (2*3) + ((2*3)+1)
非常好。回到我的想法,我认为这应该可以通过以下方式对我的applicative
实现进行重做:
auto sf = applicative<std::string>{}
.then([](std::string const& s) {return s.size() * 4; })
.then([](int k) {return k - 2; });
std::cout << sf.eval_with("hello world"); << "\n";
如您所见,这是一种惰性评估,我们仅在需要时才使用eval_with
来提供价值。我一直在考虑如何实现这个新版本一小时,而且我不知道在哪里存储操作和组合函数,applicative
模板参数的内容,就像我们在std::string
处所做的那样还有更多问题。一个人将如何实现这样的目标?是否像我最初希望的那样琐碎,还是需要大量代码?我真的很想要这样做,因为我认为这样可以避免在函数的长链上传递大量参数,从而使我受益匪浅。
编辑:我正在做更多工作,结果发现我链接的compose
实现并不是我真正想到的,因为我们仍在执行链中的所有函数调用并仍在传递参数。但是您可以回答,假设任何compose
函数都可以工作,并且选择更好的compose
实现是性能优化。我的想法更像是遵循我的例子
applicative<std::string>{"hello world"}
.then([](std::string const& s) {return s.size() * 4; })
.then([](int k) {return k - 2; })
.and_last([](int k) { std::cout << k << "\n"; });
这些then
调用将导致与(s.size() * 4) - 2
等效的单个函数调用,可以使用eval_with
进行评估。
答案 0 :(得分:2)
这就是你想要的吗?
#include <iostream>
#include <string>
struct id
{
template <typename T>
auto operator()(T t) const
{
return t;
}
};
template <typename T, typename Func = id>
struct applicative {
applicative(Func f = Func())
: _f(f)
{
}
template <typename Fn>
auto then(Fn f) const {
auto composition = [=](T val) { return f(_f(val)); };
return applicative<T, decltype(composition)>(composition);
}
auto eval_with(T t)
{
return _f(t);
}
Func _f;
};
int main() {
auto sf = applicative<std::string>{}
.then([](std::string const& s) {return s.size() * 4; })
.then([](int k) {return k - 2; });
std::cout << sf.eval_with("hello world") << "\n";
}
免责声明:我并不担心完美的转发,因此一切都是通过价值传递的。