--In this example, we define a silly Point type, which is just a pair -- of "coordinates" of the same type. It could hold a point in 2D space, -- or a pair of strings to identify a square on a map like <"1", "A">, -- or whatever else. We just want to custom-print it. -- To make it more interesting, let's add a "point at infinity", a special value -- actually popular in geometry (cf. "projective geometry"): Prelude> data Point a = Pt a a | Infty -- Pt is ready for both building full points and lambdas via partial application: -- This is a function! It doesn't print, but it does work. Prelude> Pt 1 :19:1: No instance for (Show (a0 -> Point a0)) arising from a use of ‘print’ In a stmt of an interactive GHCi command: print it Prelude> :t Pt 1 Pt 1 :: Num a => a -> Point a Prelude> let f = Pt 1 -- Not quote there: we can't "show" the Point yet. Prelude> f 2 :22:1: No instance for (Show (Point a0)) arising from a use of ‘print’ In a stmt of an interactive GHCi command: print it Prelude> :t show show :: Show a => a -> String -- We need to add an instance of Show for Point. First try: Prelude> instance Show (Point a) where show Pt x y = "<" ++ show x ++ ", " ++ show y ++ ">" :24:36: Constructor ‘Pt’ should have 2 arguments, but has been given none In the pattern: Pt In an equation for ‘show’: show Pt x y = "<" ++ show x ++ ", " ++ show y ++ ">" In the instance declaration for ‘Show (Point a)’ -- Duh, classic syntax error: no parens around the pattern, so the pattern is mistaken -- for a function application (reread the above error message to see this). Second try: Prelude> instance Show (Point a) where show (Pt x y) = "<" ++ show x ++ ", " ++ show y ++ ">" :25:54: No instance for (Show a) arising from a use of ‘show’ Possible fix: add (Show a) to the context of the instance declaration In the first argument of ‘(++)’, namely ‘show x’ In the second argument of ‘(++)’, namely ‘show x ++ ", " ++ show y ++ ">"’ In the expression: "<" ++ show x ++ ", " ++ show y ++ ">" -- We used "show" on x and y, but who says they have it? Well, we need to---as the -- error message above hints. Third try: Prelude> instance Show a => Show (Point a) where show (Pt x y) = "<" ++ show x ++ ", " ++ show y ++ ">" -- It works: Prelude> :t Pt 1 3 Pt 1 3 :: Num a => Point a Prelude> Pt 1 3 <1, 3> -- And it works for f : Prelude> let f = Pt 1 Prelude> f 2 <1, 2> Prelude> f 3 <1, 3> Prelude> f 5 <1, 5> -- Not for strings, though, as expected: Prelude> f "foo" :31:1: No instance for (Num [Char]) arising from a use of ‘f’ In the expression: f "foo" In an equation for ‘it’: it = f "foo" Prelude> :t f f :: Num a => a -> Point a -- But, we forgot to define how Infty gets printed! Prelude> Infty *** Exception: :26:41-94: Non-exhaustive patterns in function show Prelude> :t Infty Infty :: Point a Prelude> :i Infty data Point a = ... | Infty -- Defined at :18:25 -- It's real, and a part of the Point a type, but has no show pattern: Prelude> Infty *** Exception: :26:41-94: Non-exhaustive patterns in function show Prelude> instance Show a => Show (Point a) where { show (Pt x y) = "<" ++ show x ++ ", " ++ show y ++ ">" ; show Intfy = "" } -- Typo: :37:105: Not in scope: data constructor ‘Intfy’ Perhaps you meant ‘Infty’ (line 18) Prelude> instance Show a => Show (Point a) where { show (Pt x y) = "<" ++ show x ++ ", " ++ show y ++ ">" ; show Infty = "" } -- Finally, it's about to work... But... --The new definition conflicts with an earlier definition that stuck around in GHCI. -- This happens occasionally; the same would happen if a function were defined twice in a file. -- Note the line numbers in the error messages; these are where the conflicting definitions occur. Prelude> Infty :39:1: Overlapping instances for Show (Point a0) arising from a use of ‘print’ Matching instances: instance Show a => Show (Point a) -- Defined at :26:10 instance Show a => Show (Point a) -- Defined at :38:10 In a stmt of an interactive GHCi command: print it -- So redefine the type to clear its older definitions: Prelude> data Point a = Pt a a | Infty Prelude> instance Show a => Show (Point a) where { show (Pt x y) = "<" ++ show x ++ ", " ++ show y ++ ">" ; show Infty = "" } -- And it finally works! :) Prelude> Infty -- show gives us a structured pretty-print of Haskell objects: Prelude> show [1,2, 4,5] "[1,2,4,5]" -- Oops, an error. A Haskell list cannot mix types like integers and Points! Prelude> show [1,2, Pt 4 7] :45:1: No instance for (Show a0) arising from a use of ‘show’ The type variable ‘a0’ is ambiguous Note: there are several potential instances: instance Show a => Show (Point a) -- Defined at :41:10 instance Show a => Show (Ghci8.Point a) -- Defined at :38:10 instance Show a => Show (Ghci8.Point a) -- Defined at :26:10 ...plus 48 others In the expression: show [1, 2, Pt 4 7] In an equation for ‘it’: it = show [1, 2, Pt 4 7] :45:7: No instance for (Num (Point a0)) arising from the literal ‘1’ In the expression: 1 In the first argument of ‘show’, namely ‘[1, 2, Pt 4 7]’ In the expression: show [1, 2, Pt 4 7] :45:15: No instance for (Num a0) arising from the literal ‘4’ The type variable ‘a0’ is ambiguous Note: there are several potential instances: instance Num Double -- Defined in ‘GHC.Float’ instance Num Float -- Defined in ‘GHC.Float’ instance Integral a => Num (GHC.Real.Ratio a) -- Defined in ‘GHC.Real’ ...plus three others In the first argument of ‘Pt’, namely ‘4’ In the expression: Pt 4 7 In the first argument of ‘show’, namely ‘[1, 2, Pt 4 7]’ -- This works, though: Prelude> show (2, (Pt 4 7)) "(2,<4, 7>)" -- Tuples allow any kind of type mixing. Prelude> show (1, 2, (Pt 4 7)) "(1,2,<4, 7>)" -- Suggestion: define arithmetic addition of Points as vectors (assume Num a => Point a). -- Define it to include addition with Infty to mean getting Infty for any point, and test. -- -- In doing so---i.e., joining a special point to a type---you will replicate some of the -- programming pattern that goes into Maybe.