diff options
| author | Jan Sucan <jan@jansucan.com> | 2024-01-27 17:31:02 +0100 |
|---|---|---|
| committer | Jan Sucan <jan@jansucan.com> | 2024-01-27 17:31:02 +0100 |
| commit | 70ac59a6845f54798a03924d498711503534fc55 (patch) | |
| tree | 632943bb013005f2a873cb14ef01d7c2d76d5dbc | |
| parent | 6b5d934a5de4c002fbf9633f781e4b5d6670a23d (diff) | |
13_a_1: Add solution
| -rw-r--r-- | README.md | 2 | ||||
| -rw-r--r-- | ch13/13_a_1.hs | 117 |
2 files changed, 118 insertions, 1 deletions
@@ -137,7 +137,7 @@ are prefixed with 'Module_'. | **_12_a_1_** | yes | 274 | 12. Barcode recognition | | 12_a_2 | yes, in 12_a_1 | | | | 12_a_3 | yes, in 12_a_1 | | | -| **_13_a_1_** | | 316 | 13. Data structures | +| **_13_a_1_** | yes | 316 | 13. Data structures | | **_14_a_1_** | | 352 | 14. Monads | | **_15_a_1_** | | 382 | 15. Programming with monads | | 15_a_2 | | | | diff --git a/ch13/13_a_1.hs b/ch13/13_a_1.hs new file mode 100644 index 0000000..a3d3fa1 --- /dev/null +++ b/ch13/13_a_1.hs @@ -0,0 +1,117 @@ +-- Extend the prettyShow function to remove unnecessary parentheses. + +{-- From examples/examples/ch13/num.hs modified according to the assignment --} +import Data.List + +data Op = Plus | Minus | Mul | Div | Pow + deriving (Eq, Show) + +data SymbolicManip a = + Number a -- Simple number, such as 5 + | Symbol String -- A symbol, such as x + | BinaryArith Op (SymbolicManip a) (SymbolicManip a) + | UnaryArith String (SymbolicManip a) + deriving (Eq) + +instance Num a => Num (SymbolicManip a) where + a + b = BinaryArith Plus a b + a - b = BinaryArith Minus a b + a * b = BinaryArith Mul a b + negate a = BinaryArith Mul (Number (-1)) a + abs a = UnaryArith "abs" a + signum _ = error "signum is unimplemented" + fromInteger i = Number (fromInteger i) + + +instance (Fractional a) => Fractional (SymbolicManip a) where + a / b = BinaryArith Div a b + recip a = BinaryArith Div (Number 1) a + fromRational r = Number (fromRational r) + +instance (Floating a) => Floating (SymbolicManip a) where + pi = Symbol "pi" + exp a = UnaryArith "exp" a + log a = UnaryArith "log" a + sqrt a = UnaryArith "sqrt" a + a ** b = BinaryArith Pow a b + sin a = UnaryArith "sin" a + cos a = UnaryArith "cos" a + tan a = UnaryArith "tan" a + asin a = UnaryArith "asin" a + acos a = UnaryArith "acos" a + atan a = UnaryArith "atan" a + sinh a = UnaryArith "sinh" a + cosh a = UnaryArith "cosh" a + tanh a = UnaryArith "tanh" a + asinh a = UnaryArith "asinh" a + acosh a = UnaryArith "acosh" a + atanh a = UnaryArith "atanh" a + + +prettyShow :: (Show a, Num a) => SymbolicManip a -> String +prettyShow (Number x) = show x +prettyShow (Symbol x) = x +prettyShow (BinaryArith op a b) = + let pa = simpleParen a op + pb = simpleParen b op + pop = op2str op + in pa ++ pop ++ pb +prettyShow (UnaryArith opstr a) = + opstr ++ "(" ++ show a ++ ")" + + +op2str :: Op -> String +op2str Plus = "+" +op2str Minus = "-" +op2str Mul = "*" +op2str Div = "/" +op2str Pow = "**" + + +simpleParen :: (Show a, Num a) => SymbolicManip a -> Op -> String +simpleParen (Number x) _ = prettyShow (Number x) +simpleParen (Symbol x) _ = prettyShow (Symbol x) +-- If a binary arithmetic expression is a neighbor of a higher priority +-- operator, it needs to be protected from it by parentheses. Otherwise, no need +-- to use parentheses as it will be evaluated with expected priority. +simpleParen x@(BinaryArith op _ _) parentOp = if opHasHigherPriority parentOp op + then "(" ++ prettyShow x ++ ")" + else prettyShow x +simpleParen x@(UnaryArith _ _) _ = prettyShow x + + +opHasHigherPriority :: Op -> Op -> Bool +opHasHigherPriority a b = (opPrio a) > (opPrio b) + where + opPrio Plus = 0 + opPrio Minus = 0 + opPrio Mul = 1 + opPrio Div = 1 + opPrio Pow = 2 + + +instance (Show a, Num a) => Show (SymbolicManip a) where + show a = prettyShow a +{-- End of code from examples --} + + +-- ghci> :l 13_a_1.hs +-- [1 of 1] Compiling Main ( 13_a_1.hs, interpreted ) +-- Ok, one module loaded. + +-- ghci> prettyShow ((Number 1) / (Number 2) * (Number 3)) +-- "1.0/2.0*3.0" + +-- ghci> prettyShow ( ( (Number 1) + (Number 2) + (Number 3) ) * (Number 4) ) +-- "(1+2+3)*4" +-- ghci> prettyShow ( (Number 1) + (Number 2) + (Number 3) * (Number 4) ) +-- "1+2+3*4" +-- ghci> prettyShow ( (Number 1) + (Number 2) + ( (Number 3) * (Number 4) ) ) +-- "1+2+3*4" + +-- ghci> prettyShow ( (Number 0) * ( (Number 1) + (Number 2) + (Number 3) ) ) +-- "0*(1+2+3)" +-- ghci> prettyShow ( (Number 0) * (Number 1) + (Number 2) + (Number 3) ) +-- "0*1+2+3" +-- ghci> prettyShow ( ( (Number 0) * (Number 1) ) + (Number 2) + (Number 3) ) +-- "0*1+2+3" |
