Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/128.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
实现Bind()(LINQ中的SelectMany)而不产生收益(在C+;+;) 我尝试在C++中实现 Ana >代码> CATA > BIN < /Cuff>(from)。我管理过Ana和Cata,但是Bind让我迷路了_C++_.net_Bind_Linq - Fatal编程技术网

实现Bind()(LINQ中的SelectMany)而不产生收益(在C+;+;) 我尝试在C++中实现 Ana >代码> CATA > BIN < /Cuff>(from)。我管理过Ana和Cata,但是Bind让我迷路了

实现Bind()(LINQ中的SelectMany)而不产生收益(在C+;+;) 我尝试在C++中实现 Ana >代码> CATA > BIN < /Cuff>(from)。我管理过Ana和Cata,但是Bind让我迷路了,c++,.net,bind,linq,C++,.net,Bind,Linq,以下是我对Ana和Cata的看法: #define FEnumerable function<function<Option<T>(void)>(void)> #define TResult function<function<Option<R>(void)>(void)> template<typename T> class Option { public: bool HasValue; T

以下是我对
Ana
Cata
的看法:

#define FEnumerable function<function<Option<T>(void)>(void)>
#define TResult function<function<Option<R>(void)>(void)>

template<typename T> class Option {
public:
    bool HasValue;
    T value;
    Option(T value) : HasValue(true), value(value) { }
    Option() : HasValue(false) { }
};

template<typename T> FEnumerable Ana(T seed, function<bool(T)> condition, function<T(T)> next) {
    auto result = [condition, next, seed]() -> function<Option<T>()> {
        return [condition, next, seed]() -> Option<T> {
            static Option<T> value;
            value = Option<T>(value.HasValue ? next(value.value) : seed);
            if (condition(value.value))
                return Option<T>(value.value);
            return Option<T>();
        };
    };
    return result;
};

template<typename T, typename R> TResult Ana(T seed, function<bool(T)> condition, function<T(T)> next, function<R(T)> translation) {
    auto result = [condition, next, seed, translation]() -> function<Option<R>()> {
        return [condition, next, seed, translation]() -> Option<R> {
            static Option<T> value;
            value = Option<T>(value.HasValue ? next(value.value) : seed);
            if (condition(value.value))
                return Option<R>(translation(value.value));
            return Option<R>();
        };
    };
    return result;
};

template<typename T, typename A> A Cata(FEnumerable source, A seed, function<A(A, T)> fn) {
    auto e = source();
    A result = seed;
    Option<T> value;
    while ((value = e()).HasValue)
        result = fn(result, value.value);
    return result;
};

template<typename T, typename A, typename R> R Cata(FEnumerable source, A seed, function<A(A, T)> fn, function<R(A)> translation) {
    auto e = source();
    R result = seed;
    Option<T> value;
    while ((value = e()).HasValue)
        result = fn(result, value.value);
    return translation(result);
};
换句话说,
Bind()
需要接受一个
FEnumerable
(惰性序列)和一个选择器函数,该函数接受单个值并返回一个值序列;然后Bind必须为每个输入值调用选择器函数一次,然后在一个大序列中返回选择器返回的所有值但很懒。作为一个
FEnumerable

作为参考,以下是C#中的效果:

foreach (var value in source)
    foreach (var result in selector(value))
        yield return result;
是的,没有收益的话会有点困难。下面是如何在C++中用懒惰的评价来看待:

list<R> results;
while ((auto value = source()).HasValue)
    while ((auto result = selector(value)).HasValue)
        results.push_back(result);
return results;
列出结果;
while((auto value=source()).HasValue)
while((自动结果=选择器(值)).HasValue)
结果。推回(结果);
返回结果;

但我需要惰性求值,这意味着嵌套lambda。如果有人走到这一步而没有头部爆炸,请帮助我。

我们可以尝试创建一个子源,即当我们迭代时,
的连续结果,作为关闭状态的一部分:

template<typename T>
TResult Bind(FEnumerable source, function<TResult(T)> selector)
{
    return [source, selector]() -> function<Option<R>()>
    {
        auto e = source();
        // Note that std::function is nullable and I am using
        // this possible state!
        // If this isn't std::function, making subsource an
        // Option<function<Option<R>()> is always a possibility
        function<Option<R>()> subsource;

        return [e, subsource, selector]() -> Option<R>
        {
            while(!subsource) {
                // This means we need to fetch a new subsource
                auto candidate = e();
                if(!candidate.HasValue) {
                    // Iteration ends here once `e` has run out
                    return Option<R>();
                } else {
                    subsource = selector(candidate.value)();
                }

                auto result = subsource();
                if(!result.HasValue) {
                    // We selected over an empty subsource, so let's
                    // try again and maybe pick a new fresh one
                    subsource = nullptr;
                    continue;
                }
                return result;
            }
        };
    };
}
模板
TResult绑定(FEnumerable源、函数选择器)
{
返回[源,选择器]()->函数
{
自动e=源();
//请注意,std::function是可为空的,我正在使用
//这种可能的状态!
//如果这不是std::function,则将子源设置为
//选择权
{
而(!子资源){
//这意味着我们需要获取一个新的子资源
自动候选=e();
如果(!candidate.HasValue){
//一旦'e'用完,迭代就在这里结束
返回选项();
}否则{
子资源=选择器(候选值)();
}
自动结果=子资源();
如果(!result.HasValue){
//我们选择了一个空的子资源,所以让我们
//再试一次,也许再挑一个新的
subsource=nullptr;
继续;
}
返回结果;
}
};
};
}
注意,这依赖于重复调用
e()
,假设每次迭代结束时都返回空的
选项。否则,您可以显式地编码“我们已经用完了子源”状态,例如,使用一个或多个闭包变量


或者,一旦迭代结束,客户机代码就有责任停止对
Bind
的结果进行迭代,在这种情况下,您也可以继续,并且
source
/
e
的结尾仍然只会到达一次。

好的,我从Luc Danton那里获取了代码,修复了一些问题,并使其正常工作。以下是寻找解决方案的其他人的代码:

template<typename T, typename R> TResult Bind(FEnumerable source, function<TResult(T)> selector) {
    return [source, selector]() -> function<Option<R>()> {
        auto e = source();
        // Note that std::function is nullable and I am using this possible state!
        // If this isn't std::function, making subsource an Option<function<Option<R>()> is always a possibility
        function<Option<R>()> subsource;
        return [e, subsource, selector]() mutable -> Option<R> {
            while (true) {
                while(!subsource) {             // This means we need to fetch a new subsource
                    auto candidate = e();
                    if (!candidate.HasValue)
                        return Option<R>();      // Iteration ends here once `source` has run out
                    subsource = selector(candidate.value)();
                }
                auto result = subsource();
                if (result.HasValue)
                    return result;
                subsource = nullptr;        // We selected over an empty subsource, so let's try again and maybe pick a new fresh one
            }
            return Option<R>();
        };
    };
}
模板TResult绑定(FEnumerable源代码,函数选择器){
返回[源,选择器]()->函数{
自动e=源();
//请注意,std::function是可空的,我使用的是这种可能的状态!
//如果这不是std::function,则将subsource作为选项{
while(true){
而(!subsource){//这意味着我们需要获取一个新的子资源
自动候选=e();
如果(!candidate.HasValue)
return Option();//一旦'source'用完,迭代就在这里结束
子资源=选择器(候选值)();
}
自动结果=子资源();
if(result.HasValue)
返回结果;
subsource=nullptr;//我们选择了一个空的子资源,所以让我们再试一次,也许可以选择一个新的
}
返回选项();
};
};
}

一个
可数的
如何不仅仅是一个
函数
?您是否希望能够重新启动?我想这是有道理的。顺便说一句,在C++14中,
boost::optional
正在进入
std
。FEnumerable是一个返回函数的函数。就像std::list可以给你一个迭代器一样,迭代器可以给你值;您可以多次询问FEnumerable的函数值,并获得不同的迭代器实例。@Sodalmaghty我有一个GitHub项目linq cpp,它将linq功能引入C++11。看起来这也是你想要做的(在某种程度上)。如果您感兴趣,请查看并与我联系。有几个bug-您忘记了
mutable
,您的
while
块包含了太多的代码,但它很接近。我把它们修好了,现在一切正常。非常感谢!我会接受你的答案,但是为任何其他闲逛的人发布一个带有固定代码的新答案。
template<typename T, typename R> TResult Bind(FEnumerable source, function<TResult(T)> selector) {
    return [source, selector]() -> function<Option<R>()> {
        auto e = source();
        // Note that std::function is nullable and I am using this possible state!
        // If this isn't std::function, making subsource an Option<function<Option<R>()> is always a possibility
        function<Option<R>()> subsource;
        return [e, subsource, selector]() mutable -> Option<R> {
            while (true) {
                while(!subsource) {             // This means we need to fetch a new subsource
                    auto candidate = e();
                    if (!candidate.HasValue)
                        return Option<R>();      // Iteration ends here once `source` has run out
                    subsource = selector(candidate.value)();
                }
                auto result = subsource();
                if (result.HasValue)
                    return result;
                subsource = nullptr;        // We selected over an empty subsource, so let's try again and maybe pick a new fresh one
            }
            return Option<R>();
        };
    };
}