```{- |
Maintainer: dev@chungyc.org

Part of Ninety-Nine Haskell "Problems".  Some solutions are in "Solutions.P75".
-}
module Problems.P75
( maybeGoldbach
-- * Original function
-- | The function below is the equivalent implementation of 'maybeGoldbach' without do notation.
, maybeGoldbach') where

import           Solutions.P40 (goldbach)
import qualified Solutions.P75 as Solution

-- \$setup
-- >>> import Problems.P74  (withFixedInput)
-- >>> import System.IO

{- |
In "Problems.P75", 'Problems.P75.askGoldbach' could not output an error if the input was not a number
or it was not an even number greater than 2.  We could implement a function which returned 'Nothing'
when the input is not valid, such as in the following.

@
maybeGoldbach :: String -> Maybe (Int, (Int,Int))
maybeGoldbach s =
Nothing -> Nothing
Just n -> if n < 2 then Nothing else
if odd n then Nothing else
Just (n, goldbach n)
@

Then we could take advantage of this function to print out an error if the input is not valid.

>>> :{
let format (n, (a,b)) = (show n) ++ "=" ++ (show a) ++ "+" ++ (show b)
s <- hGetLine hIn
case maybeGoldbach s of
Nothing -> hPutStrLn hOut "error"
Just x  -> hPutStrLn hOut \$ format x
in do
withFixedInput "not a number" stdout maybeAskGoldbach
:}
104=3+101
error

However, the implementation of @maybeGoldbach@ above is a chain of conditional expressions.
It is not problematic in this particular case, but can make things awkward when there
are many conditions and successful operations that need to happen
for a function to return a 'Maybe' value.

and rewrite @maybeGoldbach@ more succintly using do notation.
returns @Just ()@ when its argument is true
and @Nothing@ when its argument is false,
would be useful for making it even more succinct.

=== Examples

>>> maybeGoldbach "104"
Just (104,(3,101))

>>> maybeGoldbach "not a number"
Nothing

>>> maybeGoldbach "1"
Nothing

>>> maybeGoldbach "101"
Nothing
-}
maybeGoldbach :: String -> Maybe (Integer, (Integer, Integer))
maybeGoldbach :: String -> Maybe (Integer, (Integer, Integer))
maybeGoldbach = String -> Maybe (Integer, (Integer, Integer))
Solution.maybeGoldbach

{- | Parses a string into a number and returns a tuple of the number and its Goldbach pair.
Returns 'Nothing' if the input is not valid.

This is an implementation of 'maybeGoldbach' without do notation.

=== Examples

>>> maybeGoldbach' "104"
Just (104,(3,101))

>>> maybeGoldbach' "not a number"
Nothing

>>> maybeGoldbach' "1"
Nothing

>>> maybeGoldbach' "101"
Nothing
-}
maybeGoldbach' :: String -> Maybe (Integer, (Integer, Integer))
maybeGoldbach' :: String -> Maybe (Integer, (Integer, Integer))
maybeGoldbach' String
s
| Just Integer
n <- String -> Maybe Integer
forall a. Read a => String -> Maybe a
s, Integer
n Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
> Integer
2, Integer -> Bool
forall a. Integral a => a -> Bool
even Integer
n = (Integer, (Integer, Integer))
-> Maybe (Integer, (Integer, Integer))
forall a. a -> Maybe a
Just (Integer
n, Integer -> (Integer, Integer)
forall a. Integral a => a -> (a, a)
goldbach Integer
n)
| Bool
otherwise = Maybe (Integer, (Integer, Integer))
forall a. Maybe a
Nothing
```