如何在不同的名称空间中放置haskell字段名称?

时间:2013-01-09 22:41:38

标签: haskell

考虑以下两种类型:

data Point=Point{x::Float,y::Float}
data Rectangle = {upperLeft::Point, bottomRight::Point}
data Square = {upperLeft::Point, bottomRight::Point}

ghc编译器抱怨Rectangle中的upperLeft字段名称与Square的字段名称冲突。这看起来很奇怪,因为从表面上看,每个字段名都应该在该类型的命名空间中,否则就不能重用字段名,而且我怀疑这是一个足够普遍的期望。

例如,要定义我们编写的变量:

let a=Rectangle{upperLeft=Point 2 3, bottomRight=Point 7 7}
let a=Square{upperLeft=Point 2 3, bottomRight=Point 7 7}

由此我们可以看出,我们应该能够期望每个字段名称应该在它们各自的类型名称空间内。

我的用法是正确还是我的期望错了?有没有办法解决这个问题?

3 个答案:

答案 0 :(得分:4)

由于可以通过字段名称访问对象,因此编译器必须能够从其字段名称中推断出对象的类型。例如,在

boundingBox x = bottomRight x - upperLeft x

访问者bottomRightupperLeft用于推断x的类型。如果允许多个类型具有相同的访问者名称,则无法推断出类型。

为避免名称冲突,常见的惯例是在所有字段名称上添加前缀。该惯例用于GHC项目。

data Rectangle = {rc_upperLeft :: Point, rc_bottomRight :: Point}
data Square =    {sq_upperLeft :: Point, sq_bottomRight :: Point}

答案 1 :(得分:3)

在Haskell中,创建记录类型也会创建访问器功能。 例如,您可以对上面定义的任一变量运行:x (upperLeft a)以获得2。 这是一个summary of record syntax

您可以选择在记录上使用不同的字段名称,也可以将它们放在单独的模块中。因为模块每个都有自己的名称空间,如果将Square放在Square模块中,将Rectangle放在Rectangle模块中,则可以重用字段名称。

答案 2 :(得分:2)

你可以将Square构造函数放在Rectangle类型中,因为它实际上更像是该类型的特化。

从GHCI中输入内容,这似乎工作正常:

data Point
    = Point{x::Float,y::Float}
    deriving (Eq, Show)

data Rectangle
    = Rectangle {upperLeft::Point, bottomRight::Point}
    | Square    {upperLeft::Point, bottomRight::Point}
    deriving (Eq, Show)

let r = Rectangle (Point 3.0 4.0) (Point 4.0 2.0)
let s = Square (Point 2.0 4.0) (Point 4.0 2.0)

然后你可以同时打电话:

upperLeft s
upperLeft r

虽然你可能想要更改Square,因为它有一些限制,它必须满足:

data Rectangle
    = Rectangle {upperLeft::Point, bottomRight::Point}
    | Square    {upperLeft::Point, size::Float}
    deriving (Eq, Show)