There's a rule for academic papers where if the author is writing in clear language, he has something interesting to say, and if he's writing in fancy academese, he's probably saying absolutely nothing.
I don't really see a huge additional value for your proposed method call semantics, can you explain more? Some(Result) can make nil go away, but you've still got the error to deal with. So you're talking some type system where a single value encapsulates Result/Nil/Error?
Specifically, try reading these completely un-academic un-papers.
'Either' monad, with nice kid-friendly pictures: http://fsharpforfunandprofit.com/posts/recipe-part2/
Bonus: Martin Fowler, of all men, endorses the above approach, in Java, of all languages: http://martinfowler.com/articles/replaceThrowWithNotificatio...
A Kleisli category, with examples in down-to-earth, compact, un-hairy C++: http://bartoszmilewski.com/2014/12/23/kleisli-categories/
This stuff is not hard and is utterly practical. It can very well be used in current industrial languages.
The worst service you can render to yourself is to start thinking that you already know all what is worth knowing, and close your mind to new concepts. Guys that thought that Fortran and Cobol are enough to get by for foreseeable future were technically correct — both are still in some demand! Unfortunately, their market share has dramatically shrunk, deservedly, as have employment opportunities.
So, no, it's not just that the words are unfamiliar. It's that the problems that they're trying to solve are so abstract that they're completely disconnected from the work that I actually do.
And before you tell me that I'm really doing this stuff without realizing it: Maybe so. That doesn't mean that my life would be improved by doing it explicitly.
It seems to me that the "everything is category theory" approach has the same over-abstraction problem that the Java "AbstractFactoryFactoryFactory" approach has, and deserves to be as frequently mocked.
Still, it's worth knowing the name for a concept so that you can talk to people about it, and it's certainly worth knowing the library tools that exist and can save you time. Pretty often I'll write two or three lines of code, look at it, and then realise "oh, that's just traverseM" or some such. Even if it doesn't save me any time writing, replacing three lines with one library call is a huge bonus to maintainability.
I work primarily in embedded systems, where sequence is critical, many things are stateful, and there are multiple threads of control. So, for example, I could take the sequential aspects and re-write them as a monad. Or I could just do nothing, and let them be sequential imperative code.
I know that in a pure functional world, sequence can be written as a monad. But why should I care? In my world, it does nothing for me. I'm not going to try to write imperative code in a monad to build an illusion of non-sequential purity when the essence of what I need to be doing is so sequential.
Worse, composing the actions means I have to think through how the composing is going to affect the sequencing of events. Just having a function doesn't give me that problem - the sequencing is explicit, not hidden, and therefore is easier to reason about.
[Thinking...]
How about a robotic hand that's supposed to pick up a ball. The (C/C++) code might look like :
void pickUpBall()
{
openHand();
moveHandToBall();
closeHand();
}
You have to have that sequence. If the hand isn't open, moving it to the ball just bumps the ball away. If you close the hand before you move to the ball, you don't pick up the ball, you just close on air.So, in Haskell (if I had the hardware control libraries), I could put that in a monad to guarantee the sequence, and in an IO monad so that I could do things that had side effects like affecting the external world. But in fact I get both of those for free, just by not writing it in Haskell. (The pure functional nature of Haskell also doesn't do much for me in this situation. Yes, for the functions that can in fact be purely functional, it can make them easier to reason about and prove correct. But that isn't the difficult part of the code.)
Composability: It's unclear to me how you're going to compose something like this in any way that's a) useful in this environment and b) dramatically different from simply making a higher-level function that calls pickUpBall() and some other functions.
Actually it might be easier to use some open source embedded code.
For completeness sake, I'd write the snippet above almost identically:
pickUpBall = do
openHand
moveHandToBall
closeHandBut if that isn't a monad, then why did you write it that way? My original claim was that a monad wouldn't do much for me in my world, and if you wrote this without a monad, that kind of seems like you're agreeing with me.
You said that you'd gain composability from writing this as a monad. In this example, how would that work? What would it buy me that I couldn't write (as easily) using what to me is the normal way?
As for whether monads would help your code (and I still think they would) I'll need a larger example. In a small example abstraction and reuse aren't really apparent.
If you can provide a larger example, we can find out who's right ;)
Alternatively I'll try to find a larger example if you can't or don't want to.
But as you do, remember the question. We're in an embedded system, with lots of situations where sequence matters, and lots of stored state. The question is, what do monads buy me in that environment?
Anyway, I do have to say that the Monad abstraction is not that useful outside of Haskell because you kinda really need Type Classes to get monads "right" and most languages don't have that. What you might end up is with specific monads like promises in JS but then the monads are just a design pattern instead of being a concrete abstraction like they are in Haskell.
In addition to that, in Haskell monads are the only way to do sequential computations with side effects because by default the language is Lazy. This means that Haskell programmers have to learn this abstraction whether they like it or not while in other languages you can avoid it better :)
foo = [bar(x) for x in quux]
Or did you ever flatten a nested list?Congratulations, you've been using one of the most widespread monads.
Monads are not artificial constructs. Monads, like functions, or loops, or conditional statements, emerge naturally when you try to describe a computation, even a simple one. This is like speaking prose without knowing that.
The Haskell types often seem to think that the computing they do is the same as the computing that everybody else does, and therefore that the problems that they want to solve are the ones that everybody else wants to solve. That's not a very accurate assumption.
Note that the code I quoted above is Python, and I have lots of stuff like that in my mundane production code (processing files, tracking transactions, counting money, etc).
Seeing as Haskell is used for general computing (including embedded software) the computing is the same. I know what you ate getting at, but I don't think it is based on facts or anything rational.
foo = [bar(x) for x in quux]
This is effectively a map, so it's strange to call it "using monads". "Using functors" would be more accurate.You can get "monad" out of list comprehensions though, when you have multiple "for" clauses.
foo = [y for x in quux for y in bar(x)]
seems equivalent to foo = quux >>= barMonad is just a way to establish a (type verified) set of rules for a sequence of functions. This set of rules can be -for example- about the management of return value of these functions : executing the next function if we get a result, returning immediately if we have an error.
What is powerful with Monads, is their genericity. They can be applied to many different contexts, and still provide the same type safety.
You're likely already building very limited/specific monads without knowing it.