开发者

Problem when trying to define Show for my Point3D type in Haskell

I am trying to define Show for my Point3D type:

type Point3D = (Integer, Integer, Integer)

instance Show Point3D where
    show (x,y,z) = "<" ++ (show x) ++ "," ++ (show y) ++ "," ++ (show z) ++ ">"

yet I must 开发者_开发技巧be missing something in the sintax, as I am always getting an error:

Illegal instance declaration for `Show Point3D'

    (All instance types must be of the form (T t1 ... tn)
     where T is not a synonym.
     Use -XTypeSynonymInstances if you want to disable this.)
In the instance declaration for `Show Point3D'

What am I doing wrong?


type Point3D = (Integer, Integer, Integer)

This code defines a name: Point3D , which is just an abbreviation of (Integer,Integer,Integer). In every context these two type expressions are equivalent. And for the latter, there is already a show instance in the Prelude defined.

If you really need a different string representation of 3d point you have the following alternatives:

  • Define a simple function formatPoint :: Point3D -> String
  • Change your type to be different from a standard 3-tuple of integers, e.g. newtype Point3D = P (Integer,Integer,Integer)
  • Enable the language extensions mentioned in the error message.

I would defer enabling language extensions until you have mastered the core of Haskell, since they have the potential of being dangerous and or confusing.

The newtype solution changes only the syntax of values not their memory representation at runtime.


As alternative to the other proposals you can define Point3D as a record:

data Point3D = Point3D { x :: Int, y :: Int, z :: Int }

instance Show Point3D where
    show (Point3D x y z) = concat ["<", show x, ",", show y, ",", show z, ">"]

Or you put the tripel inside a new type:

data Point3D = Point3D (Int, Int, Int)

instance Show Point3D where
    show (Point3D (x,y,z)) = concat ["<",(show x),",",show y,",",show z,">"]

See http://learnyouahaskell.com/making-our-own-types-and-typeclasses for the pros and cons of these versions.

[Edit]

I learned that it's better to write the last version as

newtype Point3D = Point3D (Int, Int, Int)

instance Show Point3D where
    show (Point3D (x,y,z)) = concat ["<",(show x),",",show y,",",show z,">"]

The newtype keyword was made for exactly this kind of situation. The advantage over data is that the compiler doesn't need to "wrap" the underlying type but can keep it as internal representation, which is both faster and "lazier".


Haskell separates the namespace of values and functions from the namespace of types, type classes, and modules by the case of the first letter of names. I.e. functions always have to start with a lowercase letter. While names of types have to start with an uppercase letter. Therefore the type class Show requires a function show.

Try it with:

type Point3D = (Integer, Integer, Integer)

instance Show Point3D where
    show (x,y,z) = show ""
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜