String.IsNullor Empty Monad

人气:675 发布:2022-10-16 标签: string c# null functional-programming monads

问题描述

我最近涉足了函数式编程的迷人世界,这主要是因为我获得了像Reaction这样的FP平台的经验,并在https://blog.ploeh.dk/之类的博客上阅读了这些经验。作为一名主要的命令式程序员,这是一个有趣的转变,但我仍然在努力摸索自己的脚步。

我有点厌倦了这样使用string.IsNullOrEmpty。很多时候,我发现自己在代码中使用

这样的表达式
_ = string.IsNullOrEmpty(str) ? "default text here" : str;

这并不是很糟糕,但假设我想将一系列选项链接到那个空值之后,例如

_ = string.IsNullOrEmpty(str) ? (
    util.TryGrabbingMeAnother() ??
    "default text here") : str;

讨厌。我宁愿要这样的东西--

_ = monad.NonEmptyOrNull(str) ??
    util.TryGrabbingMeAnother() ??
    "default text here";

如样例所示,我正在使用一个我称为Monad的函数来帮助将string.IsNullOrEmpty简化为可空链的操作:

public string NonEmptyOrNull(string source) =>
    string.IsNullOrEmpty(source) ? null : source;
我的问题是,这是正确的术语吗?我知道Nullable<T>可以被认为是一个单体(参见Can Nullable be used as a functor in C#?和Monad in plain English? (For the OOP programmer with no FP background))。这些材料是很好的参考资料,但我仍然没有足够的直观把握这个主题,知道我在这里是否只是混淆或不一致。例如,我知道monad应该像我上面一样启用函数链接,但它们也是类型放大器--所以我的小示例似乎行为像是启用链接的monad,但似乎将NULL/EMPTY转换为NULL是缩减而不是放大,所以我质疑这是否实际上是。那么,对于这个特殊的应用程序,谁能告诉我,谁稍微有一点经验的FP告诉我,它是否准确地称为NonEmptyOrNullMonad,以及为什么不是?

推荐答案

这更像是筛选操作。在C#中,您可以习惯地将其称为Where。如果我们更明确地区分缺失值和填充值,可能会更容易看到,这可以使用the Maybe container:

public static Maybe<T> Where<T>(
    this Maybe<T> source,
    Func<T, bool> predicate)
{
    return source.SelectMany(x => predicate(x) ? x.ToMaybe() : Maybe.Empty<T>());
}
只有几个containers支持筛选。最常见的两种是Maybe(又名Option)和各种集合(即IEnumerable<T>)。

在Haskell(它有一个比C#更强大的类型系统)this is enabled中,通过一个名为MonadPlus的类,但我认为类型类Alternative实际上应该足以实现过滤。Alternativeis described作为应用函子上的么半群。我不确定这是否特别有帮助。

使用上面的Where方法,您可以像IsNullOrEmpty这样检查Maybe值:

var m = "foo".ToMaybe();
var inspected = m.Where(s => !string.IsNullOrEmpty(s));

这将使m原封不动地通过,而以下内容不会:

var m = "".ToMaybe();
var inspected = m.Where(s => !string.IsNullOrEmpty(s));

您可以使用Nullable<T>执行相同的操作,但我将把它作为练习

您也可以使用C#8的新的可空引用类型语言功能来实现,但我还没有尝试过。

805