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";
如示例所示,我正在使用我称为 monad 的函数来帮助将 string.IsNullOrEmpty
减少为可空链接的操作:
public string NonEmptyOrNull(string source) =>
string.IsNullOrEmpty(source) ? null : source;
我的问题是,这是正确的术语吗?我知道 Nullable<T>
可以被认为是一个 monad(参见 and Monad in plain English? (For the OOP programmer with no FP background))。这些材料是很好的参考资料,但我对这个主题的直觉把握仍然不够充分,无法判断我是否只是在混淆或前后矛盾。例如,我知道 monad 应该像我上面所说的那样启用函数链接,但它们也是“类型放大器”——所以我的小例子似乎 表现 像一个用于启用链接的 monad ,但似乎将 null/empty 转换为 null 是 减少 而不是放大,所以我怀疑这实际上是否 是 单子。因此,对于这个特定的应用程序,对 FP 有更多经验的人可以告诉我将 NonEmptyOrNull
称为 monad 是否准确,为什么或为什么不正确?
我相信这通常在 FP 范例中比验证 null
提前一步解决。 str
值绝不能为 null
。相反,原始方法必须 return 一个空集合。这样,方法链接就不必验证 null。下一个操作将不会执行,因为没有要操作的元素
您可以找到多个参考资料。在互联网上与此相关。 https://www.informit.com/articles/article.aspx?p=2133373&seqNum=5 是我可以快速抓住的
我是从 Pluralsight 的 Zoran Horvat 课程中学到的。如果您确实可以访问,请检查一下。课程名称是“
.NET 中的战术设计模式:控制流”,模块是“空对象和特例模式”
考虑到对 FP 的兴趣,Zoran Horvat 还开设了其他课程,帮助转换或使 OO 代码更具功能性。我很高兴能在这里做出回应,因为最近我也一直在研究 FP。祝你好运!
一个单子是一个三元组,包括:
- 单参数类型构造函数
M
- 类型为
a -> M a
的函数 unit
- 类型为
M (M a) -> a
的函数 join
满足单子定律。
类型构造函数是一个类型级函数,它接受多个类型参数和 returns 一个类型。 C# 不直接具有此功能,但是在编码 monad 时,您需要一个单参数泛型类型,例如List<T>
、Task<T>
等。因此,对于某些泛型类型 M
,您需要两个函数,它们从单个值构造泛型类型的实例,一个 'flattens' 的嵌套实例方式。例如 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); }
从这个定义可以看出单个函数不能满足monad的定义,所以你的例子不是monad的例子
根据这个定义,Nullable<T>
也没有monad实例,因为无法构造嵌套类型Nullable<Nullable<T>>
,所以join
无法实现。
这更像是一个 filter 操作。在 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 via a class named MonadPlus
, but I think that the type class Alternative
actually ought to be enough to implement filtering. Alternative
is described 作为应用函子上的 幺半群。 我不确定不过,这特别有用。
使用上述 Where
方法,您可以将 Maybe
值通过检查 IsNullOrEmpty
像这样:
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 的新 可空引用类型 语言功能来实现,但我还没有尝试过。
我最近一直在涉足函数式编程的迷人世界,这主要是因为获得了像 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";
如示例所示,我正在使用我称为 monad 的函数来帮助将 string.IsNullOrEmpty
减少为可空链接的操作:
public string NonEmptyOrNull(string source) =>
string.IsNullOrEmpty(source) ? null : source;
我的问题是,这是正确的术语吗?我知道 Nullable<T>
可以被认为是一个 monad(参见 NonEmptyOrNull
称为 monad 是否准确,为什么或为什么不正确?
我相信这通常在 FP 范例中比验证 null
提前一步解决。 str
值绝不能为 null
。相反,原始方法必须 return 一个空集合。这样,方法链接就不必验证 null。下一个操作将不会执行,因为没有要操作的元素
您可以找到多个参考资料。在互联网上与此相关。 https://www.informit.com/articles/article.aspx?p=2133373&seqNum=5 是我可以快速抓住的
我是从 Pluralsight 的 Zoran Horvat 课程中学到的。如果您确实可以访问,请检查一下。课程名称是“ .NET 中的战术设计模式:控制流”,模块是“空对象和特例模式”
考虑到对 FP 的兴趣,Zoran Horvat 还开设了其他课程,帮助转换或使 OO 代码更具功能性。我很高兴能在这里做出回应,因为最近我也一直在研究 FP。祝你好运!
一个单子是一个三元组,包括:
- 单参数类型构造函数
M
- 类型为
a -> M a
的函数 - 类型为
M (M a) -> a
的函数
unit
join
满足单子定律。
类型构造函数是一个类型级函数,它接受多个类型参数和 returns 一个类型。 C# 不直接具有此功能,但是在编码 monad 时,您需要一个单参数泛型类型,例如List<T>
、Task<T>
等。因此,对于某些泛型类型 M
,您需要两个函数,它们从单个值构造泛型类型的实例,一个 'flattens' 的嵌套实例方式。例如 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); }
从这个定义可以看出单个函数不能满足monad的定义,所以你的例子不是monad的例子
根据这个定义,Nullable<T>
也没有monad实例,因为无法构造嵌套类型Nullable<Nullable<T>>
,所以join
无法实现。
这更像是一个 filter 操作。在 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 via a class named MonadPlus
, but I think that the type class Alternative
actually ought to be enough to implement filtering. Alternative
is described 作为应用函子上的 幺半群。 我不确定不过,这特别有用。
使用上述 Where
方法,您可以将 Maybe
值通过检查 IsNullOrEmpty
像这样:
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 的新 可空引用类型 语言功能来实现,但我还没有尝试过。