[英]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
unit
a -> M a
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.