繁体   English   中英

String.IsNullOrEmpty 单子

[英]String.IsNullOrEmpty Monad

我最近涉足函数式编程的迷人世界,主要是因为获得了 React 等 FP 平台的经验,并阅读了https://blog.ploeh.dk/之类的博客。 作为一个主要的命令式程序员,这是一个有趣的转变,但我仍然试图让我的脚湿透。

我有点厌倦了这样使用string.IsNullOrEmpty 很多时候,我发现自己在代码中乱扔垃圾,比如

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

这还不错,但是说我想在 null 之后链接一堆选项,例如

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

呸。 我宁愿有这样的东西——

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

如示例所示,我正在使用 function ,我将其称为 monad 以帮助将string.IsNullOrEmpty减少为可空链接的操作:

public string NonEmptyOrNull(string source) =>
    string.IsNullOrEmpty(source) ? null : source;

我的问题是,这是正确的术语吗? 我知道Nullable<T>可以被认为是一个 monad(请参阅Can Nullable 可以用作 C# 中的函子吗?Monad 是简单的英语?(对于没有 FP 背景的 OOP 程序员) )。 这些材料是很好的参考资料,但我对这个主题的直觉理解还不够,无法知道我在这里是否只是在混淆或不一致。 例如,我知道 monad 应该像上面那样启用 function 链接,但它们也是“类型放大器”——所以我的小例子似乎表现得像一个启用链接的 monad,但它似乎将 null/empty 转换为只是 null 是减少而不是放大,所以我怀疑这是否真的一个单子。 因此,对于这个特定的应用程序,有更多 FP 经验的人能否告诉我将NonEmptyOrNull称为 monad 是否准确,为什么或为什么不呢?

monad 是一个三元组,包括:

  • 单参数类型构造函数M
  • A 型 function unit a -> M a
  • A function join类型M (M a) -> a

满足单子定律。

类型构造函数是一个类型级别的 function,它接受多个类型 arguments 并返回一个类型。 C# 不直接具有此功能,但是在编码 monad 时,您需要一个单参数泛型类型,例如List<T>Task<T>等。因此对于某些泛型类型M ,您需要两个构造泛型实例的函数来自单个值的类型,“展平”该类型的嵌套实例。 例如对于List<T>

public static List<T> unit<T>(T value) { return new List<T> { value }; }
public static List<T> join<T>(List<List<T>> l) { return l.SelectMany(l => l); }

从这个定义可以看出,单个 function 不能满足 monad 的定义,所以你的例子不是 monad 的例子。

根据这个定义, Nullable<T>也没有 monad 实例,因为嵌套类型Nullable<Nullable<T>>无法构造,因此无法实现join

这更像是一个过滤操作。 在 C# 中,您习惯性地称它为Where 如果我们更明确地区分缺失值和填充值,可能会更容易看出,我们可以使用Maybe 容器来做到这一点:

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>());
}

只有少数 容器支持过滤。 最常见的两个是Maybe (AKA Option )和各种 collections (即IEnumerable<T> )。

在 Haskell (它具有比 C# 更强大的类型系统) 中,这是通过名为MonadPlus的 class 启用的,但我认为 class Alternative类型实际上应该足以实现过滤。 Alternative 被描述应用函子上的一个幺半群。 不过,我不确定这是否特别有用。

使用上面的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 的新的可空引用类型语言功能来做到这一点,但我还没有尝试过。

我相信这通常在 FP 范例中解决,比验证null提前一步。 str值绝不能是null 相反,原始方法必须返回一个空集合。 这样,方法链就不必验证 null。 下一个操作将不会执行,因为没有要操作的元素

您可以找到多个参考资料。 互联网上与此相关。 https://www.informit.com/articles/article.aspx?p=2133373&seqNum=5是我可以快速抓取的一个

我从 Pluralsight 的 Zoran Horvat 课程中学到了这一点。 如果您有访问权限,请检查一下。 课程名称为“Tactical Design Patterns in .NET: Control Flow”,模块为“Null Object and Special Case Patterns”

考虑到对 FP 的兴趣,Zoran Horvat 还提供了其他有助于转换或使 OO 代码更实用的课程。 在这里回复我很兴奋,因为最近我也在研究 FP。 祝你好运!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM