Homework/HW1.fedorind.hs

160 lines
3.1 KiB
Haskell

module HW1 where
--
-- * A simple arithmetic expression language
--
-- | A representation of arithmetic expressions as binary trees where leaves
-- are literal integers and internal nodes are either addition or
-- multiplaction nodes. Note that this data structure is an "abstract
-- syntax tree", which is something we will spend more time talking about
-- later in the course.
data Expr
= Lit Int -- ^ Literal integers
| Add Expr Expr -- ^ Addition expressions
| Mul Expr Expr -- ^ Multiplication expressions
deriving (Eq,Show)
fold :: (Int -> a) -> (a -> a -> a) -> (a -> a -> a) -> Expr -> a
fold f1 f2 f3 = rec
where
rec (Lit i) = f1 i
rec (Add l r) = f2 (rec l) (rec r)
rec (Mul l r) = f3 (rec l) (rec r)
instance Num Expr where
(+) = Add
(*) = Mul
fromInteger = Lit . fromInteger
-- | The expression: 2 + 3 * 4
e1 :: Expr
e1 = Add (Lit 2) (Mul (Lit 3) (Lit 4))
-- | The expression: (7 + 6) * 5
e2 :: Expr
e2 = Mul (Add (Lit 7) (Lit 6)) (Lit 5)
-- | The expresssion: 3 * 2 + 5 * 4
-- Make sure to take standard operator precedence into account.
e3 :: Expr
e3 = 3 * 2 + 5 * 4 -- :)
-- | The expression: 8 + 7 * 9 + 6
-- Make sure to take standard operator precedence into account.
e4 :: Expr
e4 = 8 + 7 * 9 + 6 -- :)
-- | The leftmost literal in an expression.
--
-- >>> leftLit (Lit 3)
-- 3
--
-- >>> leftLit e1
-- 2
--
-- >>> leftLit e2
-- 7
--
leftLit :: Expr -> Int
leftLit = fold id const const
-- | The rightmost literal in an expression.
--
-- >>> rightLit (Lit 3)
-- 3
--
-- >>> rightLit e3
-- 4
--
-- >>> rightLit e4
-- 6
--
rightLit :: Expr -> Int
rightLit = fold id (flip const) (flip const)
-- | Get the maximum literal value in an expression.
--
-- >>> maxLit (Lit 3)
-- 3
--
-- >>> maxLit e1
-- 4
--
-- >>> maxLit e2
-- 7
--
-- >>> maxLit e3
-- 5
--
-- >>> maxLit e4
-- 9
--
maxLit :: Expr -> Int
maxLit = fold id max max
-- | The integer result of evaluating an expression.
--
-- >>> eval (Lit 3)
-- 3
--
-- >>> eval e1
-- 14
--
-- >>> eval e2
-- 65
--
-- >>> eval e3
-- 26
--
-- >>> eval e4
-- 77
--
eval :: Expr -> Int
eval = fold id (+) (*)
-- | Render an expression as a string (called "pretty printing").
--
-- My solution only adds parentheses when strictly necessary, but it's
-- easier to add them conservatively (that is, to add more than you need).
-- It's OK if your solution adds more parentheses as long as they don't
-- change the meaning of the expression--feel free to tweak the tests to
-- make them pass.
--
-- >>> pretty (Lit 3)
-- "3"
--
-- >>> pretty e1
-- "2 + 3 * 4"
--
-- >>> pretty e2
-- "(7 + 6) * 5"
--
-- >>> pretty e3
-- "3 * 2 + 5 * 4"
--
-- >>> pretty e4
-- "8 + 7 * 9 + 6"
--
-- >>> pretty (Add e1 e2)
-- "2 + 3 * 4 + (7 + 6) * 5"
--
-- >>> pretty (Mul e1 e2)
-- "(2 + 3 * 4) * (7 + 6) * 5"
--
pretty :: Expr -> String
pretty (Lit n) = show n
pretty (Add l r) = pretty l ++ " + " ++ pretty r
pretty (Mul l r) = prettyMul l ++ " * " ++ prettyMul r
where
prettyMul e@Add{} = "(" ++ pretty e ++ ")"
prettyMul e = pretty e