```{- |
Description: Supporting definitions for monad problems
Maintainer: dev@chungyc.org

-}
module Problems.Monads (Operator (..), Element (..), parsePostfix) where

import           Data.Char (isDigit)

-- | Encodes an operator for a mathematical expression.
data Operator
-- | Encodes negation.  Equivalent to an unary minus.  Unary operator.
= Negate
-- | Encodes duplication.  Makes another copy of its operand.  Unary operator.
-- | Encodes subtraction.  Binary operator.
| Subtract
-- | Encodes multiplication.  Binary operator.
| Multiply
-- | Encodes division.  Equivalent to 'div'.  Binary operator.
| Divide
-- | Encodes a modulo operator.  Equivalent to 'mod'.  Binary operator.
| Modulo
deriving (Operator -> Operator -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Operator -> Operator -> Bool
\$c/= :: Operator -> Operator -> Bool
== :: Operator -> Operator -> Bool
\$c== :: Operator -> Operator -> Bool
Eq, Int -> Operator
Operator -> Int
Operator -> [Operator]
Operator -> Operator
Operator -> Operator -> [Operator]
Operator -> Operator -> Operator -> [Operator]
forall a.
(a -> a)
-> (a -> a)
-> (Int -> a)
-> (a -> Int)
-> (a -> [a])
-> (a -> a -> [a])
-> (a -> a -> [a])
-> (a -> a -> a -> [a])
-> Enum a
enumFromThenTo :: Operator -> Operator -> Operator -> [Operator]
\$cenumFromThenTo :: Operator -> Operator -> Operator -> [Operator]
enumFromTo :: Operator -> Operator -> [Operator]
\$cenumFromTo :: Operator -> Operator -> [Operator]
enumFromThen :: Operator -> Operator -> [Operator]
\$cenumFromThen :: Operator -> Operator -> [Operator]
enumFrom :: Operator -> [Operator]
\$cenumFrom :: Operator -> [Operator]
toEnum :: Int -> Operator
\$ctoEnum :: Int -> Operator
pred :: Operator -> Operator
\$cpred :: Operator -> Operator
succ :: Operator -> Operator
\$csucc :: Operator -> Operator
Enum, Operator
forall a. a -> a -> Bounded a
maxBound :: Operator
\$cmaxBound :: Operator
minBound :: Operator
\$cminBound :: Operator
Bounded, Int -> Operator -> ShowS
[Operator] -> ShowS
Operator -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Operator] -> ShowS
\$cshowList :: [Operator] -> ShowS
show :: Operator -> String
\$cshow :: Operator -> String
showsPrec :: Int -> Operator -> ShowS
\$cshowsPrec :: Int -> Operator -> ShowS
Show)

-- | A single element within a mathematical expression.
-- A list of these elements comprises an expression in postfix notation.
data Element = Operator Operator | Operand Integer deriving (Element -> Element -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Element -> Element -> Bool
\$c/= :: Element -> Element -> Bool
== :: Element -> Element -> Bool
\$c== :: Element -> Element -> Bool
Eq, Int -> Element -> ShowS
[Element] -> ShowS
Element -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Element] -> ShowS
\$cshowList :: [Element] -> ShowS
show :: Element -> String
\$cshow :: Element -> String
showsPrec :: Int -> Element -> ShowS
\$cshowsPrec :: Int -> Element -> ShowS
Show)

-- | Parses a string containing a mathematical expression in postfix notation.
-- This can make it easier to write down an expression in a more conventional form.
--
-- For example,
--
-- >>> parsePostfix "3 4 2 - *"
-- [Operand 3,Operand 4,Operand 2,Operator Subtract,Operator Multiply]
--
-- The operators are encoded as follows:
--
-- +-------------+------------------+
-- | Operator    | String           |
-- +=============+==================+
-- | 'Negate'    | @"negate"@       |
-- +-------------+------------------+
-- | 'Add'       | @"+"@            |
-- +-------------+------------------+
-- | 'Subtract'  | @"-"@            |
-- +-------------+------------------+
-- | 'Multiply'  | @"*"@            |
-- +-------------+------------------+
-- | 'Divide'    | @"/"@            |
-- +-------------+------------------+
-- | 'Modulo'    | @"%"@            |
-- +-------------+------------------+
parsePostfix :: String -> [Element]
parsePostfix :: String -> [Element]
parsePostfix String
expr = forall a b. (a -> b) -> [a] -> [b]
map String -> Element
parseToken forall a b. (a -> b) -> a -> b
\$ String -> [String]
words String
expr

parseToken :: String -> Element
parseToken :: String -> Element
parseToken String
x
| forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all Char -> Bool
isDigit String
x = Integer -> Element
Operand (forall a. Read a => String -> a
x)
| String
x forall a. Eq a => a -> a -> Bool
== String
"negate" = Operator -> Element
Operator Operator
Negate
| String
x forall a. Eq a => a -> a -> Bool
== String
"+" = Operator -> Element
Operator Operator
| String
x forall a. Eq a => a -> a -> Bool
== String
"-" = Operator -> Element
Operator Operator
Subtract
| String
x forall a. Eq a => a -> a -> Bool
== String
"*" = Operator -> Element
Operator Operator
Multiply
| String
x forall a. Eq a => a -> a -> Bool
== String
"/" = Operator -> Element
Operator Operator
Divide
| String
x forall a. Eq a => a -> a -> Bool
== String
"%" = Operator -> Element
Operator Operator
Modulo
| Bool
otherwise = forall a. HasCallStack => a
undefined
```