In Haskell, if a function returns a “Maybe a” type just so it is safe and total, how is it useful anymore?

  • A+

So I have to define a safe version of the head function that would not throw an error when [] is passed as the argument. Here it is:

safeHead :: [a] -> Maybe a safeHead [] = Nothing safeHead (x:_) = Just x 

But now, is this function still of any use? Because suppose that type "a" is a Int, then you can add two objects of type Int, but you can't add two objects of type "Maybe Int".


"Just" is one such function. Here's how you can use its result (for the ghci REPL):

import Data.Foldable (sequenceA_)  let writeLn            = putStrLn . show  let supposedlyUnusable = writeLn <$> Just 0  sequenceA_ supposedlyUnusable 

which prints 1 or we can continue to try the other interesting example - using the Nothing case

let supposedlyUnusable = writeLn <$> Nothing  sequenceA_ supposedlyUnusable 

which doesn't print anything.

That's a complete program which works even for other instances of Traversable or Foldable where you couldn't do a case analysis on the Maybe value. <$> is the key that lets you apply a function to whatever's contained in the Maybe or any Functor and if you have two Maybes (or two of the same Applicative) you can use the pattern fn <$> applicative_a <*> applicative_b which is like fn a b but where a and b are wrapped up things like Maybe values.

So that leaves a couple of remaining ways to use a Maybe that I can think of, all of which use case analysis:

let {fn (Just n) = Just $ 1 + n; fn Nothing  = Nothing} fn v -- but that was just a messy way of writing (1+) <$> v 


let fn v = case v of {Just n -> Just $ 1 + n; Nothing -> Nothing} -- and that's the same program with a different syntax 


import Data.Maybe (fromMaybe) fromMaybe someDefault v -- and that extracted the `value` from `v` if we had `Just value` or else gave us `someDefault` 


let {fn (Just n) = writeLn n; fn Nothing = putStrLn "No answer"} -- this one extracts an action but also provides an action when there's nothing -- it can be done using <$> and fromMaybe instead, but beginners tend to -- find it easier because of the tutorials that resulted from the history -- of the base library's development let fn v = fromMaybe (putStrLn "No answer") (writeLn <$> v) 

oooh, oooh! This one's neato:

import Control.Applicative let v = Just 0 -- or Nothing, if you want let errorcase = pure $ putStrLn "No answer" let successcase = writeLn <$> v sequenceA_ $ successcase <|> errorcase -- that uses Alternative in which Maybe tries to give an answer preferring the earliest if it can 

of course we also have the classic:

maybe (putStrLn "No answer") writeLn v 


:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: