aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan Sucan <jan@jansucan.com>2024-01-27 17:31:02 +0100
committerJan Sucan <jan@jansucan.com>2024-01-27 17:31:02 +0100
commit70ac59a6845f54798a03924d498711503534fc55 (patch)
tree632943bb013005f2a873cb14ef01d7c2d76d5dbc
parent6b5d934a5de4c002fbf9633f781e4b5d6670a23d (diff)
13_a_1: Add solution
-rw-r--r--README.md2
-rw-r--r--ch13/13_a_1.hs117
2 files changed, 118 insertions, 1 deletions
diff --git a/README.md b/README.md
index a1f2127..6d2b5b1 100644
--- a/README.md
+++ b/README.md
@@ -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"