Being able to abstract over monads (and other type constructors) ... that's the part that really matters.
C# is not expressive enough for that.
It is actually possible to get most of the way to HKT using extension methods. But it involves a hell of a lot of typing. In my project I used a template generator to do it. It's still pretty limited though, and there isn't a single type-class called Monad.
That's what I referred to.
> ...
The point is that you can't leverage all the existing monad/functor/applicative/free/yoneda... libraries out there–they don't exist, because they can't be written in a way that would allow re-use.
Agreed. I can only hope one day that the CLR team decide it's a reasonable thing to support so that C# (and F#) can both support it. It seems to be the blockage to the language teams (they won't move without it, even if they could implement it in a weaker/slower way on top of the existing type system). I've jumped through many hoops to get as much of a functional 'base class library' as possible in C# (I needed it for a very large C# project I maintain and want to bring more stability to), but language support would be preferred.
Monad Transformers for one. Traverse/Sequence are another super common (amazing) pattern that requires abstracting over types.
http://eed3si9n.com/learning-scalaz-day12
is a nice tutorial series on it.
So in F# I've been using specialized asyncSeq and asyncMaybe libraries. With monad transformers (and thus HKT's), would those come largely for free?
And you could traverse a list<maybe<list<_>> combo like [Some [Some [1; 2]; None; Some [3]]; None; Some [None; Some [4]]] with no more difficulty than a regular list-of-lists?
You can also write a generic "sequence" over a list, for instance, so that any 'monad' (task/future, maybe/option, state, either/disjunction etc.) can 'swap places'.
So your List<Future<A>> can become Future<List<A>>. But you only need to write it once. Then it doesn't matter what the inner type of the List is, as long as it's a monad (applicative, really, but all monads are applicatives).
Now looking at the Scalaz impl, the transformers are actually the core thing, and monads themselves are just transformers over Identity. So it all fits and isn't redundant. Certainly changes a lot of perspective.
[1] https://github.com/louthy/language-ext/blob/master/LanguageE...
But that still doesn't change the crux of the blog post, it's disingenuous comparing the Option monad to a null coalescing operator.
Ruby 2.3 &. operator and Swift can do something like this pseudocode:
if let city = article?.author?.address?.city?.ToLower() {
// city present
}
Too long?: if let city = article?
.author?
.address?
.city?
.ToLower() {
// city present
}
All are improvements over pyramids of doom.(Be aware of subtle gotcha in Scala of var and val, really prefer Rust/Go/Swift keywords.)
Or you can go the whole hog like I have my language-ext project [1][2].
In C# it would look like this:
Which is arguably even more elegant than the Scala 'for' notation.As an aside, there was a discussion [3] on one of the language-ext issues about my Try<T> implementation, and I was asked to compare it to Scala's Try monad. The crux of it was that it's perfectly possible to capture the majority of the use-cases, but may be of interest in the context of this discussion.
[1] https://github.com/louthy/language-ext
[2] https://github.com/louthy/language-ext/blob/master/LanguageE...
[3] https://github.com/louthy/language-ext/issues/33#issuecommen...