The one principle i know about the Maybe type is that we shouldn’t use it when there is more than one failure reason, however if i use monadic functions in the construction of my Maybe value there are exactly 0 generic ways to decipher why i have a Nothing value in the case i do.
Also it isn’t like there are no alternatives assuming you can’t add non boot dependencies you can easily use the (Either SomeException) monad and this also allows you to use all the exception stuff in Control.Monad.Catch.
If you can add a dependency in a library with polymorphic variants you can have even more correctness, eliminating errors partially instead of being forced to handle all possible Exceptions to eliminate
given these facts is there a situation where the Maybe Monad Instance is the best option?
I have had many occassions when there is only failure reason or the reason is irrelevant to my plan B. The most boring example is Data.Map[.Strict].lookup; slightly less boring example is when I’m going for catMaybes . map (lookup foo).
Did it never occur to you a situation that you get a Nothing in a function which uses the Maybe Monad Instance(probably do syntax) to produce the final value and then you waste a ton of time looking into which of the monadic function calls generates the failure?
How do you reliably prevent this situation? i am not against Maybe only all uses of (>>=) instantiated on this type.
Seems like this is an argument against using Nothing to represent errors you may want to diagnose, not an argument against using Monad Maybe ever.
If Nothing means ‘unnecessary’, for example, then it’s perfectly reasonable to use it monadically; you’re expressing that you don’t care why you don’t need a thing. If you do care why, you have the wrong type.
When you do a database query with left joins and you retrieve 10 fields per row which might be null and you want to do something with them (it’s not an error and you don’t want to log the nulls).
Programming is the art of controlled forgetfulness. After all pure logic can only forget information, it can never create new information. You use the Maybe monad whenever it provides precisely the right kind of forgetting you need.
A lot of the container code returns Nothing for a nonexistent value. So if you ever need to chain lookups (lookup in map A, then if it exists lookup in map B) the maybe Monad is perfect for this.
yes and once again the problem is that when you will eventually get a Nothing you won’t know which of the Maybes failed. Once again although for each individual function a Maybe may make sense a Maybe produced monadically is always bad as it has at least 2 possible different failure reasons
It only matters which one failed if you care which one failed. You’re welcome to not like it and not use it in your code. Asserting that it is always bad is a bit dictatorial for the rest of us.
??? having the opinion that something is bad and discussing it. Is inherently dictatorial ??? “using unsafePeformIO is bad long term. Don’t use it” that is dictatorial??
If not please enlighten me on what is the dictatorial difference between this and “using the Maybe Monad Instance(>>=) is bad. Don’t use it”? also the worst wrong answer is “the second is dictatorial because i disagree with it”.
How could anything discussed on this Forum be dictatorial without being about moderation? also even assuming definition 2 of merriam webster.
i don’t think i have been Oppressive, Arrogant or Overbearing? if i have been unintentionally could you point exactly how so that i can learn for next time?
anyways code changes. How do you know when to convert your own code from Maybe to some other error handling monad like (Either SomeException) ?
I really don’t know how to do this consistently and frequently mistakenly under consider the consequences of a consumer of my code needing to know about which monadic values are Nothing.
I have many considerations like this but talking about all of them simultaneously would distract from those a consider most important, thanks for the understanding.
I was thinking that rather than making a big left to right case pattern matching (or nesting cases if some items must be combined with others) over 10 values you can use do notation (thus, >>=) and it’s easier to structure, top to bottom, no extra indentation. Easier to look at when you start progressing through the items.
I can kind of see where you’re coming from. The only time I find it super necessary are when:
Working with nested lookups
Sequencing functions that can fail –> but even here I find Applicative Maybe more useful.
I think it’s fine whenever Nothing is representing “there is nothing useful I can do with the result of this computation” and if a sequence of monadic Maybe actions can be sequenced to represent one big idea (i.e, all of these procedures in this specific sequence must pass, otherwise, any single failure in here will be handled equally).
Maybe is definitely overused and I’ve committed sins of this sort myself, which I’ve lived to regret.
That said, not all Nothings get reported. One good example is transforming an AST by spotting certain patterns in it. You define things like viewLambdaApplication :: Term -> Maybe Term, viewConstant :: Term -> Maybe Constant etc, chain them together and if you get a Nothing, it’s fine, you move on to trying the same thing with a subtree or just give up.
i am not saying to not use do notation, i am fully in favor of using do notation with a better error-monad like (Either SomeException) or anything equivalent to VEither from vary, just don’t do so when your type is maybe.
I find the Monad instances for Maybe and Either e useful, but unlike monads that are used to organise side-effects, there’s usually less complicated control flow and less reason to use large do-blocks. So when I choose to use a do-block with them, I’ll often write Just or Right instead of pure because they’re relatively uncommon.
EDIT: I also do this with the list monad, writing [foo] at the end of a block of code to make things clearer.
The core misunderstanding here is that Nothing is always to be interpreted as some kind of failure. But Maybe x is simply the monad of sub-sets of x with cardinality at most one. In that role, Maybe is perfectly fine as it is, as other have pointed out.
Of course you are right that conflating meaningfully different kinds of failure is bad programming style.