如何在不同的名称空间中放置haskell字段名?
考虑以下两种类型:如何在不同的名称空间中放置haskell字段名?,haskell,Haskell,考虑以下两种类型: data Point=Point{x::Float,y::Float} data Rectangle = {upperLeft::Point, bottomRight::Point} data Square = {upperLeft::Point, bottomRight::Point} ghc编译器抱怨矩形中左上角的字段名与正方形的字段名冲突。这似乎很奇怪,因为从表面上看,每个字段名都应该在类型的命名空间中,否则就不能重用字段名,我怀疑这是一个足够常见的期望 例如,要定义
data Point=Point{x::Float,y::Float}
data Rectangle = {upperLeft::Point, bottomRight::Point}
data Square = {upperLeft::Point, bottomRight::Point}
ghc编译器抱怨矩形中左上角的字段名与正方形的字段名冲突。这似乎很奇怪,因为从表面上看,每个字段名都应该在类型的命名空间中,否则就不能重用字段名,我怀疑这是一个足够常见的期望
例如,要定义我们编写的变量:
let a=Rectangle{upperLeft=Point 2 3, bottomRight=Point 7 7}
let a=Square{upperLeft=Point 2 3, bottomRight=Point 7 7}
从这里我们可以看到,我们应该能够期望每个字段名都应该在它们各自的类型名称空间中
我的用法是正确的还是我的期望是错误的?有没有办法解决这个问题?在Haskell中,创建记录类型也会创建访问器函数。 例如,您可以在上面定义的任一变量上运行:
x(左上角a)
,得到2。
这是一个例子
您可以选择在记录上使用不同的字段名,或者将它们放在单独的模块中。因为每个模块都有自己的名称空间,如果您将Square放在Square模块中,将Rectangle放在Rectangle模块中,您将能够重用字段名。您可以将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
尽管您可能希望更改正方形,因为它必须满足一些约束:
data Rectangle
= Rectangle {upperLeft::Point, bottomRight::Point}
| Square {upperLeft::Point, size::Float}
deriving (Eq, Show)
由于对象可以通过其字段名访问,因此编译器必须能够从其字段名推断对象的类型。例如,在
boundingBox x = bottomRight x - upperLeft x
访问器bottomRight
和upperLeft
用于推断x
的类型。如果允许多个类型具有相同的访问器名称,则无法推断该类型
为了避免名称冲突,一个常见的约定是在所有字段名称上都加上前缀。GHC项目中使用了此约定
data Rectangle = {rc_upperLeft :: Point, rc_bottomRight :: Point}
data Square = {sq_upperLeft :: Point, sq_bottomRight :: Point}
将每种类型放在自己的模块中似乎有些过分。我意识到已经创建了访问器函数,但我更希望类型推断能够选择正确的字段名来使用。是的,我同意在这种情况下,将其拆分为模块感觉有点过头了。我可能只是更改字段名。类似于
rect upperLeft
的东西并不比upperLeft
长一吨。我同意重复使用字段名似乎是一件有用且合理的事情,但据我所知,Haskell的记录无法做到这一点。