尝试在Haskell中为我的Point3D类型定义Show时出现问题

dev*_*ium 3 haskell functional-programming

我正在尝试为我的Point3D类型定义Show :

type Point3D = (Integer, Integer, Integer)

instance Show Point3D where
    show (x,y,z) = "<" ++ (show x) ++ "," ++ (show y) ++ "," ++ (show z) ++ ">"
Run Code Online (Sandbox Code Playgroud)

但我必须在sintax中遗漏一些东西,因为我总是收到一个错误:

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'
Run Code Online (Sandbox Code Playgroud)

我究竟做错了什么?

jmg*_*jmg 8

type Point3D = (Integer, Integer, Integer)

此代码定义了一个名称:Point3D,它只是一个缩写(Integer,Integer,Integer).在每个上下文中,这两个类型表达式是等价的 而对于后者,已经Prelude定义了一个展示实例.

如果您确实需要3d点的不同字符串表示,则可以使用以下替代方法:

  • 定义一个简单的函数 formatPoint :: Point3D -> String
  • 将您的类型更改为与标准的3元组整数不同,例如 newtype Point3D = P (Integer,Integer,Integer)
  • 启用错误消息中提到的语言扩展.

我会推迟启用语言扩展,直到你掌握了Haskell的核心,因为它们有可能是危险或混乱.

newtype解决方案仅在运行时更改值的语法而不更改其内存表示.


Lan*_*dei 6

作为其他提议的替代方案,您可以将Point3D定义为记录:

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, ">"]
Run Code Online (Sandbox Code Playgroud)

或者你把tripel放在一个新类型中:

data Point3D = Point3D (Int, Int, Int)

instance Show Point3D where
    show (Point3D (x,y,z)) = concat ["<",(show x),",",show y,",",show z,">"]
Run Code Online (Sandbox Code Playgroud)

有关这些版本的优缺点,请参见http://learnyouahaskell.com/making-our-own-types-and-typeclasses.

[编辑]

我了解到最好将最后一个版本写为

newtype Point3D = Point3D (Int, Int, Int)

instance Show Point3D where
    show (Point3D (x,y,z)) = concat ["<",(show x),",",show y,",",show z,">"]
Run Code Online (Sandbox Code Playgroud)

newtype关键字是为正是这种情况作出.优点data是编译器不需要"包装"底层类型,但可以将其保持为内部表示,这既快又"懒惰".