问题
I have lately been dipping my feet into the fascinating world of functional programming, largely due to gaining experience in FP platforms like React and reading up on blogs the likes of https://blog.ploeh.dk/. As a primarily imperative programmer, this has been an interesting transition, but I am still trying to get my wet feet under me.
I am getting a little tired of using string.IsNullOrEmpty
as such. So much of the time I find myself littering my code with expressions such as
_ = string.IsNullOrEmpty(str) ? "default text here" : str;
which isn't so bad as it goes, but say I wanted to chain a bunch of options past that null, e.g.
_ = string.IsNullOrEmpty(str) ? (
util.TryGrabbingMeAnother() ??
"default text here") : str;
Yuck. I'd much rather have something like this --
_ = monad.NonEmptyOrNull(str) ??
util.TryGrabbingMeAnother() ??
"default text here";
As the sample indicates, I am using a function that I am referring to as a monad to help reduce string.IsNullOrEmpty
to a null-chainable operation:
public string NonEmptyOrNull(string source) =>
string.IsNullOrEmpty(source) ? null : source;
My question is, is this proper terminology? I know Nullable<T>
can be considered a monad (see Can Nullable be used as a functor in C#? and Monad in plain English? (For the OOP programmer with no FP background)). These materials are good references, but I still don't have quite enough an intuitive grasp of the subject to know if I'm not just being confusing or inconsistent here. For example, I know monads are supposed to enable function chaining like I have above, but they are also "type amplifiers" -- so my little example seems to behave like a monad for enabling chaining, but it seems like converting null/empty to just null is a reduction rather than an amplification, so I question whether this actually is a monad. So for this particular application, could someone who has a little more experience with FP tell me whether or not it is accurate to call NonEmptyOrNull
a monad, and why or why not?
回答1:
I believe this is usually solved in the FP paradigm a step ahead of validating null
. The str
value must never be null
. Instead the original method must return an empty collection. This way the chaining of methods do not have to validate null. The next operation will not execute since there are no elements to operate on
There are multiple references you can find. related to this on the internet. https://www.informit.com/articles/article.aspx?p=2133373&seqNum=5 is one I could quickly grab
I learnt this from Zoran Horvat course in Pluralsight. If you do have access please check it out. The course name is " Tactical Design Patterns in .NET: Control Flow" and the module is "Null Object and Special Case Patterns"
Taking about interest in FP, Zoran Horvat also has other courses that help convert or make OO code more fuctional. I'm quite excited in responding here because lately I've been looking into FP as well. Good luck!
回答2:
A monad is a triple consisting of:
- A single-argument type constructor
M
- A function
unit
of typea -> M a
- A function
join
of typeM (M a) -> a
which satisfies the monad laws.
A type constructor is a type-level function which takes a number of type arguments and returns a type. C# doesn't have this feature directly but when encoding monads, you need a single-argument generic type e.g. List<T>
, Task<T>
etc. For some generic type M
you therefore need two functions which construct an instance of the generic type from a single value, an 'flattens' a nested instance of the type. For example for 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); }
From this definition you can see that a single function cannot satisfy the definition ofa monad, so your example is not an example of a monad.
By this definition, Nullable<T>
also does not have a monad instance since the nested type Nullable<Nullable<T>>
cannot be constructed, so join
cannot be implemented.
来源:https://stackoverflow.com/questions/62895696/string-isnullorempty-monad