Sunday, July 12, 2009

Solutions to Chapter 13 (p. 316)

#1. The decision about dropping the parentheses depends on which side of the operator we're on. So, here's the new prettyShow -- changes in bold:

prettyShow :: (Show a, Num a) => SymbolicManip a -> String

-- Show a number or symbol as a bare number or serial
prettyShow (Number x) = show x
prettyShow (Symbol x) = x

prettyShow (BinaryArith op a b) =
    let pa = maybeLeftParen a op
        pb = maybeRightParen b op
        pop = op2str op
        in pa ++ pop ++ pb
prettyShow (UnaryArith opstr a) =
    opstr ++ "(" ++ show a ++ ")"

Now, for the helper functions. Let's start with handling the left-paren:

maybeLeftParen :: (Show a, Num a) => SymbolicManip a -> Op -> String
maybeLeftParen x@(BinaryArith op1 _ _) op
   | op1 == op && isRightAssociative op = "(" ++ prettyShow x ++ ")"
   | (opPrio op1) < (opPrio op) = "(" ++ prettyShow x ++ ")"
   | otherwise = prettyShow x
maybeLeftParen x _ = simpleParen x

For this to work, we need to know each operator's priority, and whether the operator is right-associative. These are trivial (the priorities are taken from Haskell's definitions; type :i (+) in ghci, for example):

opPrio :: Op -> Int
opPrio Plus = 6
opPrio Minus = 6
opPrio Mul = 7
opPrio Div = 7
opPrio Pow = 8

isRightAssociative :: Op -> Bool
isRightAssociatove Pow = True
isRightAssociative _ = False

Finally, for handling parenthesis to the right of the operator, we have this:

maybeRightParen :: (Show a, Num a) => SymbolicManip a -> Op -> String
maybeRightParen x@(BinaryArith op1 _ _) op
   | prio1 < prio = "(" ++ prettyShow x ++ ")"
   | prio1 == prio && opIsMinusOrDiv = "(" ++ prettyShow x ++ ")"
   | otherwise = prettyShow x
   where prio1 = opPrio op1
         prio = opPrio op
         opIsMinusOrDiv = (op == Minus) || (op == Div)
maybeRightParen x _ = simpleParen x

No comments:

Post a Comment