C# 如何在有结果时停止执行并将结果返回给monad

C# 如何在有结果时停止执行并将结果返回给monad,c#,linq,monads,C#,Linq,Monads,我特别需要一种反向的单子,当它是“无”时,它将继续尝试获取一个值,并保留它获取的第一个有效值 我试图概括我在这里的意思: public void Test() { var r = from x in SomeActionToGetResult() from y in Stop() from z in SomeOtherActionToGetResult() select x | y | z; } public Ma

我特别需要一种反向的单子,当它是“无”时,它将继续尝试获取一个值,并保留它获取的第一个有效值

我试图概括我在这里的意思:

public void Test()
{
    var r = from x in SomeActionToGetResult()
            from y in Stop()
            from z in SomeOtherActionToGetResult()
            select x | y | z;
}

public Maybe<Result> SomeActionToGetResult()
{
    return new Result().Unit();
}

public Maybe<Result> SomeOtherActionToGetResult()
{
    return new Result().Unit();
}

public Maybe<Result> Stop()
{
    return new Nothing<Result>();
}
Unit函数与普通函数类似,但Bind函数给我带来了麻烦:

public static Maybe<U> Bind<T, U>(this Maybe<T> m, Func<T, Maybe<U>> k)
{
    if (!m.HasAValidValue)
        return k(m.Value);

    return m; // <--- problem right here
}
公共静态可能绑定(这可能是m,Func k)
{
如果(!m.HasAValidValue)
返回k(m值);
返回m;//(这可能对您没有任何帮助,在这种情况下,我将删除它。如果您正在与单子玩耍,这很可能是在教我的祖母吸鸡蛋,但是…)

您是否知道C#已经在语言级别上使用了此功能

如果您需要以更基于库的形式实现这一点,这很好(我会看看我能想到什么),但是如果您可以使用现有的操作符,我会的

编辑:我试过你的拼图,我认为基本上它不适合LINQ。问题主要与LINQ在
SelectMany
中期望的类型有关。例如,你的第二行有效地转换为:

SomeActionToGetResult().SelectMany(x => Stop(), (x, y) => new { x, y });
这里的问题是:

  • Stop()
    表达式中,我们不使用
    x
    的值,从逻辑上讲,我们不能使用,因为我们只希望在
    x
    的计算结果为
    None
  • 匿名类型不一定与
    SomeActionToGetResult()
    的返回类型的
    T
    部分的类型相同,因此我们无法将其转换为
    Maybe
    。我们必须引入一个新类型来提取它们
然后,当我们有:

select x | y | z
从逻辑上讲,这是你唯一能拥有的东西吗?拥有它有意义吗

select z | y | x
如果是这样,那意味着什么?我们无法避免
SomeActionToGetResult()
从执行开始,因为扩展方法只对该方法调用的结果起作用……因此,要么必须忽略投影,并且您始终计算
x
,然后计算
y
,然后计算
z
——要么您接受排序不会始终准确保留

从根本上说,我怀疑你这里没有真正的单子,否则我会期望它合适——但我在数学方面没有足够的能力来说。

(这可能对你没有任何帮助,在这种情况下,我将删除它。如果你在玩单子,这很可能是在教我祖母吸鸡蛋,但是……)

您是否知道C#已经在语言级别上使用了此功能

如果您需要以更基于库的形式实现这一点,这很好(我会看看我能想到什么),但是如果您可以使用现有的操作符,我会的

编辑:我试过你的拼图,我认为基本上它不适合LINQ。问题主要与LINQ在
SelectMany
中期望的类型有关。例如,你的第二行有效地转换为:

SomeActionToGetResult().SelectMany(x => Stop(), (x, y) => new { x, y });
这里的问题是:

  • Stop()
    表达式中,我们不使用
    x
    的值,从逻辑上讲,我们不能使用,因为我们只希望在
    x
    的计算结果为
    None
  • 匿名类型不一定与
    SomeActionToGetResult()
    的返回类型的
    T
    部分的类型相同,因此我们无法将其转换为
    Maybe
    。我们必须引入一个新类型来提取它们
然后,当我们有:

select x | y | z
从逻辑上讲,这是你唯一能拥有的东西吗?拥有它有意义吗

select z | y | x
如果是这样,那意味着什么?我们无法避免
SomeActionToGetResult()
从执行开始,因为扩展方法只对该方法调用的结果起作用……因此,要么必须忽略投影,并且您始终计算
x
,然后计算
y
,然后计算
z
——要么您接受排序不会始终准确保留


从根本上说,我怀疑你这里没有真正的单子,否则我会期望它合适-但我在数学方面没有足够的能力来说。

谢谢你的快速回答。我知道空合并运算符,我想我实际上可以使用它,但从方法返回空表示“停止处理”看起来有点模糊,我只是想让它更清楚。我的“可能”将在我的程序中命名为“停止”,只是为了熟悉这里才把它叫做:)…我最近经常碰到这个问题,现在我开始怀疑是否有可能把它说得尽可能清楚。我遇到的另一个例子是,我遇到了这个问题——空合并运算符不可用——是当monad携带多个值来确定它的b时ehavior@asgerhallas:在这种情况下,你可以使用
元组
,我可以考虑实现适当的
SelectMany
(etc)调用,我会看看今晚我能做些什么。尽管没有承诺……哦,那确实很好!:)@asgerhallas:已经编辑过,但我认为你不会喜欢我的结论:(感谢您的快速回答。我知道空合并运算符,我想我实际上可以使用它,但是从方法返回空表示“停止处理”似乎有点模糊,我只是想让它更清楚。我的“Maybe”将在我的程序中命名为“StopOr”,只是为了熟悉,在这里称它为Maybe:)…我最近经常碰到这个问题,现在我开始怀疑是否有可能把它说得尽可能清楚。我遇到的另一个例子是,当单子携带多个值来确定它的行为时,null合并运算符不可用。@asgerhallas:您可以使用
Tuple
在这种情况下…我可以考虑为这类事情执行适当的
选择许多
(等)调用-我将看看今晚我能做些什么。尽管没有承诺…哦,那将是b