我特别需要一种反向的可能monad,当它是“Nothing”时会继续尝试获取一个值,并保持它获得的第一个有效值。
我试图概述我的意思:
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>();
}
Result类如下所示:
public class Result
{
public static Result operator |(Result a, Result b)
{
if (a != null)
return a;
return b;
}
}
单位功能与正常情况一样,但是绑定功能给我带来了麻烦:
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
没有价值 - 尝试运行k()
以获得有效值。如果m
已有值,我将使用该值,并且永远不会运行k()
。
T和U从同一类型开始 - 但只要linq查询中的匿名类型启动,我就不能再依赖它了。
这有可能吗?
答案 0 :(得分:1)
(这个
您是否知道C#已经在语言级别使用null-coalescing operator?
var r = SomeActionToGetResult() ?? Stop() ?? SomeOtherActionToGetResult();
如果你需要在一个更基于库的形式中实现这一点,那很好(我会看到我能想到的)但是如果你可以只使用现有的运算符,我会
编辑:我已经解决了你的难题,我认为基本上它不适合LINQ。问题主要与LINQ在SelectMany
中期望的类型有关。例如,您的第二行有效地转换为:
SomeActionToGetResult().SelectMany(x => Stop(), (x, y) => new { x, y });
问题在于:
x
表达式中使用Stop()
的值,逻辑不能,因为我们只希望它如果x
评估为None
T
的{{1}}部分类型不同,因此我们无法将其转换为SomeActionToGetResult()
。我们必须引入一种新类型来提取它们。然后我们有:
Maybe<T>
这在逻辑上是唯一的东西吗?
是否有意义?select x | y | z
如果是这样,那意味着什么?我们不能避免select z | y | x
被执行开始,因为扩展方法只适用于该方法调用的结果...所以要么必须忽略投影而你始终评估SomeActionToGetResult()
,然后评估x
,然后评估y
- 或者您接受排序并不总是完全保留。
从根本上说,我怀疑你