{- |
Description: Either monad
Copyright: Copyright (C) 2023 Yoo Chung
License: GPL-3.0-or-later
Maintainer: dev@chungyc.org

Some solutions to "Problems.P76" of Ninety-Nine Haskell "Problems".
-}
module Solutions.P76 (eitherGoldbach) where

import           Solutions.P40 (goldbach)
import           Text.Read     (readMaybe)

-- | Rewrite of 'Problems.P75.maybeGoldbach' to return an 'Either' value.
eitherGoldbach :: String -> Either String (Integer, (Integer, Integer))
eitherGoldbach :: String -> Either String (Integer, (Integer, Integer))
eitherGoldbach String
s = do
  Integer
n <- Maybe Integer -> Either String Integer
readNumber (Maybe Integer -> Either String Integer)
-> Maybe Integer -> Either String Integer
forall a b. (a -> b) -> a -> b
$ String -> Maybe Integer
forall a. Read a => String -> Maybe a
readMaybe String
s
  if Integer
n Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
> Integer
2 then () -> Either String ()
forall a b. b -> Either a b
Right () else String -> Either String ()
forall a b. a -> Either a b
Left String
"not greater than 2"
  if Integer -> Bool
forall a. Integral a => a -> Bool
even Integer
n then () -> Either String ()
forall a b. b -> Either a b
Right () else String -> Either String ()
forall a b. a -> Either a b
Left String
"not an even number"
  (Integer, (Integer, Integer))
-> Either String (Integer, (Integer, Integer))
forall a. a -> Either String a
forall (m :: * -> *) a. Monad m => a -> m a
return (Integer
n, Integer -> (Integer, Integer)
forall a. Integral a => a -> (a, a)
goldbach Integer
n)

-- From the result of 'readMaybe', return either the number or a @"not a number"@ error.
-- 'Text.Read.readEither' could have been used,
-- except we want to use a specific error string instead of a library-defined one.
readNumber :: Maybe Integer -> Either String Integer
readNumber :: Maybe Integer -> Either String Integer
readNumber Maybe Integer
Nothing  = String -> Either String Integer
forall a b. a -> Either a b
Left String
"not a number"
readNumber (Just Integer
n) = Integer -> Either String Integer
forall a b. b -> Either a b
Right Integer
n