从迭代函数应用程序中生成一个范围

Make a range from Iterated function application

本文关键字:一个 范围 函数 迭代 应用程序      更新时间:2024-09-21

如果我有一个函数

std::array<unsigned,2> fib(std::array<unsigned,2> p)
{
return {p[1],p[1]+p[0]};
}

我想有一种方法优雅地生成无限程

[x,fib(x),fib(fib(x)),fib(fib(fib(x))),...]

这种情况经常出现,我需要找到最好的方法来做到这一点?

我发现这个回购的生成器运行良好:

template<typename F, typename Arg>
tl::generator<Arg> iterated_application(F fn, Arg x) {
while (true) {
co_yield x;
x = fn(x);
}
}

可以用作

int main() 
{
auto fib = [](auto a) {return std::array{ a[1],a[1] + a[0] }; };
for (auto i : iterated_application(fib, std::array{ 0,1 }) 
| std::views::keys 
| std::views::take(10))
std::cout << i << std::endl;
}

https://godbolt.org/z/v73zvY9cM

您可以始终创建自己的迭代器:

template<typename Arg>
struct impl_iterated_application {
using value_type = Arg;
using difference_type = std::ptrdiff_t;
using iterator_category = std::forward_iterator_tag;
const Arg& operator*() const { return current; }
impl_iterated_application& operator++() 
{ 
current = fn(current); 
return *this; 
}
auto operator++(int) { auto temp = *this; ++* this; return temp; }

impl_iterated_application(std::function<Arg(Arg)>  f = std::identity{}, Arg initial = {}) : current(initial), fn(f)
{}
//bool operator==(const impl_iterated& other) const = default;
private:
Arg current;
std::function<Arg(Arg)> fn;
};

你会在这个工厂功能中使用:

template<typename F, typename Arg>
auto iterated_application(F fn, Arg x)
{
return std::ranges::subrange(impl_iterated_application(std::function<Arg(Arg)>{fn}, x), std::unreachable_sentinel);
}

https://godbolt.org/z/dxvn54ffv

我认为联合程序生成器就是这样做的。我应该试着https://github.com/lewissbaker/cppcoro工作

我想你可能有点滥用,使用部分和,忽略调整范围中的第一个元素:

auto fib = ranges::views::repeat(std::array{ 0,1 })
| ranges::views::partial_sum([](auto a, auto){ return std::array{ a[1], a[0] + a[1] }; });
for (auto elem : fib |  ranges::views::take(10))
std::cout << elem[0] << std::endl;
可变lambda也适用于
template<typename Arg, std::invocable<Arg> F>
auto iterated_application(F fn, Arg x)
{
return ranges::views::generate(
[p = x, f=fn]() mutable
{
auto p0 = p;
p = f(p);
return p0;
});
}