以功能性方式组合谓词,并允许短路工作 [英] Combining predicates in a functional way and allowing short-circuiting to work

查看:68
本文介绍了以功能性方式组合谓词,并允许短路工作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我问了类似的问题:说我有一个谓词 auto p1 = [](int x){return x>2;} 和谓词 auto p2 = [](int x){return x<6;} ,如何结合 p1 p2 以获得 p1and2 ,以使 p1and2(x)== p1(x)&&p2(x)?答案是使用 boost :: hana :: demux (有关详细信息,请参阅链接的问题).

I asked a similar question: say I have a predicate auto p1 = [](int x){ return x > 2; } and a predicate auto p2 = [](int x){ return x < 6; }, how do I combine p1 and p2 to obtain p1and2 such that p1and2(x) == p1(x) && p2(x)? The answer was use boost::hana::demux (refer to the linked question for details).

但是,有时,仅当另一个谓词评估为给定的真值时,才对一个谓词进行评估. true .

Sometimes, however, the evaluation of one predicate should occur only if the other predicate evaluates to a given truthness value, e.g. true.

例如,一个谓词可能是

constexpr auto has_value = [](std::optional<int> opt){ return opt.has_value(); };

和其他谓词

constexpr auto has_positive = [](std::optional<int> opt){ return opt.value() == 3; };

很容易识别以下内容

bool b1 = has_value(some_opt_int) && has_positive(some_opt_int); // true or false, but just fine either way
bool b2 = has_positive(some_opt_int) && has_value(some_opt_int); // runtime error if !some_opt_int.has_value()

定义

constexpr auto all = boost::hana::demux([](auto const&... x) { return (x && ...); });

并像这样使用它

std::optional<int> empty{};
contexpr auto has_value_which_is_positive = all(has_value, has_positive);
bool result = has_value_which_is_positive(empty);

将导致运行时失败,因为这是对包装在 all中的可变参数通用lambda的函数调用 .会强制对其参数而不是对折叠表达式(x&& ...) 进行评估.

would lead to failure at run time, because the it's the function call to the variadic generic lambda wrapped in all which forces the evaluation of its arguments, not the fold expression (x && ...).

所以我的问题是,如何结合 has_value has_positive 来获得 has_value_which_is_positive ?更一般而言,我该如何和"几个谓词加在一起,以便仅根据短路机制的要求对其进行评估?

So my question is, how do I combine has_value and has_positive to get has_value_which_is_positive? More in general, how do I "and" together several predicates such that they're evaluated only as much as the short-circuit mechanism requires?

我认为,为了防止对谓词进行求值,我可以将它们包装在一些函数对象中,将这些对象应用于参数( std :: optional )时,会将其返回另一个将谓词和 std :: optional 包装在一起的对象,并且具有 operator bool 转换函数,该函数仅在对fold表达式求值时才会触发.

I think that, in order to prevent the predicates from being evaluated, I can have wrap them in some function objects which, when applied to the argument (the std::optional), give back another object which wraps the predicate and the std::optional together, and has an operator bool conversion function which would be triggered only when the fold expression is evaluated.

这是我的尝试,这是未定义的行为,因为 main 中的断言有时会失败,而有时不会:

This is my attempt, which is miserably undefined behavior because the assertion in main sometimes fails and sometimes doesn't:

#include <optional>

#include <boost/hana/functional/demux.hpp>
#include <boost/hana/functional/curry.hpp>

template<typename P, typename T>
struct LazilyAppliedPred {
    LazilyAppliedPred(P const& p, T const& t)
        : p(p)
        , t(t)
    {}
    P const& p;
    T const& t;
    operator bool() const {
        return p(t);
    }
};

constexpr auto lazily_applied_pred = [](auto const& p, auto const& t) {
    return LazilyAppliedPred(p,t);
};

auto constexpr lazily_applied_pred_curried = boost::hana::curry<2>(lazily_applied_pred);

constexpr auto all_true = [](auto const&... x) { return (x && ...); };

constexpr auto all = boost::hana::demux(all_true);

constexpr auto has_value = [](std::optional<int> o){
    return o.has_value();
};
constexpr auto has_positive = [](std::optional<int> o){
    assert(o.has_value());
    return o.value() > 0;
};

int main() {
    assert(all(lazily_applied_pred_curried(has_value),
               lazily_applied_pred_curried(has_positive))(std::optional<int>{2}));
}

(后续问题.)

推荐答案

我刚刚意识到做我描述的临时lambda实际上非常简洁:

I've just realized that an ad-hoc lambda to do what I described is actually very terse:

#include <assert.h>
#include <optional>

constexpr auto all = [](auto const& ... predicates){
    return [&predicates...](auto const& x){
        return (predicates(x) && ...);
    };
};

constexpr auto has_value = [](std::optional<int> o){
    return o.has_value();
};
constexpr auto has_positive = [](std::optional<int> o){
    assert(o.has_value());
    return o.value() > 0;
};

int main() {
    assert(all(has_value, has_positive)(std::optional<int>{2}));
    assert(!all(has_value, has_positive)(std::optional<int>{}));
}

但是,>折叠表达式中仍然存在一些短路,这并不能说服我...

这篇关于以功能性方式组合谓词,并允许短路工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆