Home > Software design >  Haskell occurring error regarding show instance
Haskell occurring error regarding show instance

Time:12-17

data Expr = Var Char | Not Expr | And Expr Expr | Or Expr Expr deriving (Eq, Ord)


instance Show Expr where
    show (Var x) = [x]
    show (Not (Var y)) = "~"   show (Var y)
    show (And (Var x) (Var y)) = show (Var x)    " ^ "    show (Var y)
    show ((Or (Var x) (Var y))) = show (Var x)    " v "    show (Var y)
    show (Not (Or (Var x) (Var y))) = "~("    show (Or (Var x) (Var y))    ")"
    show (And (Var x) (And (Var y) (Var z))) = show (Var x)    " ^ "    "("    show (And (Var y) (Var z))    ")"

I`m not sure exactly why i get this error when i run:

>(Not (Not (Var 'a')))
*** Exception: (21,5)-(26,112): Non-exhaustive patterns in function show

Can anyone help me.

CodePudding user response:

An And can also contain another And, so for example And (And (Var 'x') (Var 'y')) (Var 'z'). In your Show instance you always assume that the parameters are Vars, that is not necessary.

You can implement the Show instance as:

instance Show Expr where
    show (Var x) = [x]
    show (Not x) = "~ ("   show x    ")"
    show (And x y) = "("    show x    " ^ "    show y    ")"
    show (Or x y) = "("    show x    " v "    show y    ")"

This will introduce a lot of parenthesis. Therefore it is better to work with a precedence parameter. In fact the Show instance already has support for this: you can work with showsPrec :: Int -> a -> String -> String. Here the Int parameter is the operator precedence of the outer context, and the first String parameter is the string that needs to be appended at the end: that is done for performance reasons.

We thus can implement this as:

instance Show Expr where
    showsPrec n (Var x) = (x :)
    showsPrec n (Not x) = showParen (n > 9) ( ('~' :) . showsPrec 10 x)
    showsPrec n (And x y) = showParen (n > 8) ((showsPrec 9 x) . (" ^ "   ) . showsPrec 9 y)
    showsPrec n (Or x y) = showParen (n > 7) ((showsPrec 8 x) . (" v "   ) . showsPrec 8 y)

Here we will show parenthesis for not if the outer countext has a precedence higher than 9, and call the showPrec with a precence 10 such that the showPrec inside will not print extra parenthesis, unless it has a precedence of 10 or higher. The same applies for the other functions.

This thus means that we can print an expression with parenthesis like:

ghci> show (Not (And (Or (Not (Var 'x')) (Var 'y')) (Var 'z')))
"~((~x v y) ^ z)"

Here the And … … will thus print parenthesis since it is called with a precedence of nine, and the threshold is 8 to print parenthesis. But there are no brackets for around ~x, since the threshold is lower than 10.

CodePudding user response:

Instead of hard-coding lots of deep expressions, you should just pattern match on the topmost constructors and then recurse down.

instance Show Expr where
  show (Var v) = [v]
  show (Not x) = "Not ("  show x  ")"
  show (And x y) = "("    show x    ") ∧ ("    ...
  show (Or x y) = ...

Remember to implement the and operators if you mention them in the show results.

infixr 3 ∧
(∧) :: Expr -> Expr -> Expr
(∧) = And

Actually it is preferred to not implement show when defining recursive-data Show instances, instead implement showsPrec which has a more sophisticated way of adding parentheses as needed.

  • Related