What's the advantage of the Monad approach? Doesn't the render function still have to check whether those Maybes contain values or not?
If you have multiple steps then the advantage is that you never have to unpack "in the middle" and you don't have to care - and the compiler has your back.
Classical example: show the street number of the user or show <None> if there is no street number. There can be multiple things missing on the way and multiple transformations might happen on the way. E.g. the user might not even have an adress saved alltogether.
In that case, you only have to "check whether those Maybes contain values or not" once at the very end.
getUser :: Maybe User
getUser = ...
getFriends :: Maybe [User]
getFriends = do
user <- getUser
let friends = getFriendsForUser user
return friends
bestFriends :: Maybe [User]
bestFriends = do
friends <- getFriends
let besties = filter isBestFriend friends
return besties
render :: IO ()
render = do
let bffs = getBestFriends
case bffs of
Just besties -> renderBestFriends besties
Nothing -> renderNoFriends
The Maybe monad itself contains the equivalent of runSafely from the article, and the syntax propagates the failure case transparently from getUser down to the choice of render function used. All without either the hassle of handling null cases, or the danger that you might forget to handle them and the code crash. Without syntax level support, its not obviously an improvement to me