2013-01-09 35 views
5

考慮以下兩種類型:如何將haskell字段名稱放在不同的名稱空間中?

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

的GHC編譯器抱怨說,在與該廣場的矩形衝突upperLeft字段名。這看起來很奇怪,因爲在它的表面上,每個字段名稱應該在類型的名稱空間中,否則不能重複使用字段名稱,並且我懷疑這會是一種常見的期望。

例如定義我們寫了一個變量:

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

從這裏我們可以看到,我們應該能夠期待每個字段的名稱應該是各自類型的命名空間內。

我的用法是否正確或我的期望是否錯誤?有沒有辦法解決這個問題?

回答

3

在Haskell中,創建記錄類型也會創建存取函數。 例如,您可以在上面定義的變量中的任一變量上運行:x (upperLeft a)以獲得2. 這裏是summary of record syntax

您的選項要麼在記錄上使用不同的字段名,要麼將它們放在單獨的模塊中。因爲模塊都有自己的名稱空間,所以如果將Square放在Square模塊中並將Rectangle放在Rectangle模塊中,則可以重新使用字段名稱。

+1

將每種類型放置在其自己的模塊中似乎是一個矯枉過正的問題。我意識到accessor函數已經創建,但我希望類型推斷能夠選擇正確的字段名稱來使用。 –

+0

是的,我同意在這種情況下分離模塊感覺像是矯枉過正。我可能只是改變字段名稱。像'rectUpperLeft'這樣的東西不比'upperLeft'長。 我同意重複使用字段名稱似乎是一個有用的和合理的事情期望,但據我所知,你不能用Haskell的記錄做到這一點。 – astrieanna

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 

雖然你可能想改變廣場,因爲它有一些限制它必須滿足:

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

因爲可以通過字段名稱訪問對象,所以co mpiler必須能夠從其字段名稱推斷對象的類型。例如,在

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} 
相關問題