Strange coincidence with instancing show features

So, I am writing a program that returns a procedure for some given arithmetic problem, so I would like to give several functions to show, so that I can print the same expression that I evaluate when testing. The problem is that this code matches (-) in the first line when it should fall to the second.

{-# OPTIONS_GHC -XFlexibleInstances #-} instance Show (t -> t-> t) where show (+) = "plus" show (-) = "minus" main = print [(+),(-)] 

returns

 [plus,plus] 

Am I just doing the print function of mortal sin in the first place, or is there a way I can get it to fit correctly?

edit: I understand that I am getting the following warning:

 Warning: Pattern match(es) are overlapped In the definition of `show': show - = ... 

I still don't know why it overlaps or how to stop it.

+6
pattern-matching haskell
source share
4 answers

As stated in sepp2k and MtnViewMark , you cannot match the coincidence of identifier values, only on constructors and, in some cases, on implicit equality checks. Thus, your instance binds any argument to the identifier, in the process of obscuring the external definition (+) . Unfortunately, this means that what you are trying to do will not and will never be able to work.

A typical solution for what you want to achieve is to define the algebraic data type "arithmetic expression" with the corresponding instance of show . Note that you can make your expression type itself an instance of Num , with numeric literals wrapped in the Literal constructor, and operations of type (+) return their arguments in conjunction with a constructor for the operation. Here is 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 xy x * y = Product xy fromInteger x = Literal (fromInteger x) evaluate (Literal x) = x evaluate (Sum xy) = evaluate x + evaluate y evaluate (Product xy) = evaluate x * evaluate y integer :: Integer integer = (1 + 2) * 3 + 4 expr :: Expression Integer expr = (1 + 2) * 3 + 4 

Awakening at GHCi:

 > integer 13 > evaluate expr 13 > expr Sum (Product (Sum (Literal 1) (Literal 2)) (Literal 3)) (Literal 4) 
+9
source share

Here you can think about it. 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 understand why this will not work? answer in pattern matching is a variable other than answer in the outer scope. So instead you have to write it like this:

 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 

Actually, this is exactly what happens when you write constants in a template. I.e:

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

converted by the compiler into something equivalent:

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

Since you want to map a function bound to (+) , and not just bind something to a (+) symbol, you need to write your code as:

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

But this will require functions to be comparable for equality. And this is generally an insoluble problem.

You might argue that you simply ask the runtime system to compare function pointers, but at the language level, the Haskell programmer does not have access to pointers. In other words, you cannot manipulate references to values ​​in Haskell (*), but the values ​​themselves. This is Haskell clean and gets referential transparency.

(*) MVar , and other such objects in the IO monad are another matter, but their existence does not invalidate the point.

+9
source share

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

There is no way to map patterns by function the way you want.

+6
source share

I solved it myself with the help of a mega-hack.

 instance (Num t) => Show (t -> t-> t) where show op = case (op 6 2) of 8 -> "plus" 4 -> "minus" 12 -> "times" 3 -> "divided" 
+1
source share

All Articles