使用take_while()更正遇到的一个错误?

时间:2015-12-07 05:32:09

标签: c++ functional-programming c++17

一个由两个整数组成的序列,每次都递减一次,另一次递减,直到它们都达到极限(149到145&153到150)。

(149, 153)
(148, 153)
(147, 153)
(146, 152)
(145, 152)
(145, 152)
(145, 151)
(145, 151)
(145, 151)
(145, 150)

此实现中存在一个错误的错误,它会生成除最后一个条目之外的所有错误。

#include <iostream>
#include "../Streams-master/source/Stream.h"
#include "boost/date_time/gregorian/gregorian.hpp"
using namespace stream;
using namespace stream::op;
int main(){
    MakeStream::counter(149,-1) | map_([](auto x){return (x >= 145)?x:145;})
        | zip_with(MakeStream::counter(153,-1) | map_([](auto x){return (x >= 150)?x:150;})
            | flat_map([](auto x){return MakeStream::repeat(x,3);}) )
        | take_while([](auto t){return std::get<0>(t) != 145 || std::get<1>(t) != 150;})
        | for_each([](auto tup){std::cout << tup << std::endl;});
    }

结果:

(149, 153)
(148, 153)
(147, 153)
(146, 152)
(145, 152)
(145, 152)
(145, 151)
(145, 151)
(145, 151)

我如何获得最后一个条目?

如果这个,想要一个 - 告诉我们 - 我们已经完成了,这是一个众所周知的问题,它是如何在函数式编程和C ++中专门处理的?

使用C++1z&amp; C++ Streams

1 个答案:

答案 0 :(得分:0)

您希望停留在第一个(…, 145, 150) 包含。不幸的是take_while不适合这个目的,因为结果流只停留在第一个违规元素之外,即它只能工作(因为没有更好的术语)。对于简化的流,这一点更为明显:

// pseudo-code
auto stream = { 1, 2, 3, 0, 0, 0, /* only zeroes after that */ };
auto pred = …;
auto x = stream | take_while(pred);
// our goal
assert( x == { 1, 2, 3, 0 } );

这里显而易见的是,take_while会在遇到的第一个pred上使用0,此时我们希望它返回true,因为我们想要收下。但是我们希望它在下一个元素上返回false,这也是 0

我可以预见的三个直接选择是个人偏好的模糊顺序:

  • 查找或编写take_while的变体,其中包含不满足谓词的第一个值
  • 重写初始流,以便可以使用不同的谓词
  • 写一个棘手且有状态的不完全谓词

这最后一种方法可能被认为有些问题,因为它假定库可以传入一个不是(严格来说)谓词的函数对象,因为它将为同一个参数返回不同的值。在我们的案例中,文档没有说太多,所以我留待你的判断。如果您对此方法没有问题,可以尝试类似的方法:

auto lawful_predicate = [](auto const& t)
{ return std::get<1>(t) != 145 || std::get<2>(t) != 150; };

auto questionable_thing = [bool not_done = true, lawful_predicate](auto const& t) mutable
{ return std::exchange(not_done, lawful_predicate(t)); }

请注意我们的作弊行为是显而易见的,因为我们必须使用decltype(questionable_thing)::operator()标记mutable。如果库需要谓词来满足例如bool(Arg const&) const;签名,不会被接受。在这种情况下,您可能会更加卑鄙(但要注意终身问题,请确保您了解这里发生了什么):

// we are now leaving inner bits around
bool innards = true;
auto the_worst_thing_ever = [&innards, lawful_predicate](auto const& t)
{ return std::exchange(innards, lawful_predicate(t)); }