Strange pattern matching with functions instancing Show

Here's a way to think about this. Consider:

answer = 42
magic = 3

specialName :: Int -> String
specialName answer = "the answer to the ultimate question"
specialName magic = "the magic number"
specialName x = "just plain ol' " ++ show x

Can you see why this won't work? answer in the pattern match is a variable, distinct from answer at the outer scope. So instead, you'd have to write this like:

answer = 42
magic = 3

specialName :: Int -> String
specialName x | x == answer = "the answer to the ultimate question"
specialName x | x == magic = "the magic number"
specialName x = "just plain ol' " ++ show x

In fact, this is just what is going on when you write constants in a pattern. That is:

digitName :: Bool -> String
digitName 0 = "zero"
digitName 1 = "one"
digitName _ = "math is hard"

gets converted by the compiler to something equivalent to:

digitName :: Bool -> String
digitName x | x == 0 = "zero"
digitName x | x == 1 = "one"
digitName _ = "math is hard"

Since you want to match against the function bound to (+) rather than just bind anything to the symbol (+), you'd need to write your code as:

instance Show (t -> t-> t) where  
 show f | f == (+) = "plus"
 show f | f == (-) = "minus"

But, this would require that functions were comparable for equality. And that is an undecidable problem in general.

You might counter that you are just asking the run-time system to compare function pointers, but at the language level, the Haskell programmer doesn't have access to pointers. In other words, you can't manipulate references to values in Haskell(*), only values themselves. This is the purity of Haskell, and gains referential transparency.

(*) MVars and other such objects in the IO monad are another matter, but their existence doesn't invalidate the point.


As sepp2k and MtnViewMark said, you can't pattern match on the value of identifiers, only on constructors and, in some cases, implicit equality checks. So, your instance is binding any argument to the identifier, in the process shadowing the external definition of (+). Unfortunately, this means that what you're trying to do won't and can't ever work.

A typical solution to what you want to accomplish is to define an "arithmetic expression" algebraic data type, with an appropriate show instance. Note that you can make your expression type itself an instance of Num, with numeric literals wrapped in a "Literal" constructor, and operations like (+) returning their arguments combined with a constructor for the operation. Here's a quick, incomplete example:

data Expression a = Literal a
                  | Sum (Expression a) (Expression a)
                  | Product (Expression a) (Expression a)
                  deriving (Eq, Ord, Show)

instance (Num a) => Num (Expression a) where
    x + y = Sum x y
    x * y = Product x y
    fromInteger x = Literal (fromInteger x)

evaluate (Literal x) = x
evaluate (Sum x y) = evaluate x + evaluate y
evaluate (Product x y) = evaluate x * evaluate y

integer :: Integer
integer = (1 + 2) * 3 + 4

expr :: Expression Integer
expr = (1 + 2) * 3 + 4

Trying it out in GHCi:

> integer
13
> evaluate expr
13
> expr
Sum (Product (Sum (Literal 1) (Literal 2)) (Literal 3)) (Literal 4)

It overlaps because it treats (+) simply as a variable, meaning on the RHS the identifier + will be bound to the function you called show on.

There is no way to pattern match on functions the way you want.