2014-01-12 90 views
7

我聽說Haskell被描述爲具有結構類型。據我所知,記錄是一個例外。例如foo不能用HRec2類型的東西調用,即使HRecHRec2在它們的字段中名義上只有不同。爲什麼Haskell沒有結構類型記錄?

data HRec = HRec { x :: Int, y :: Bool } 
data HRec2 = HRec2 { p :: Int, q :: Bool } 

foo :: HRec -> Bool 

是否有一些解釋拒絕擴展結構打字的一切,包括記錄?

是否存在靜態類型化的語言,即使對於記錄也要進行結構化打字?有沒有關於這方面的爭論,我可以通讀所有靜態類型語言?

+0

這似乎更像是一個郵件列表的問題,而不是一個SO一個 - 研發語言進化史和理由不是一個真正的編程問題。但我並沒有真正致力於這個想法。 – millimoose

+0

我瘋狂的猜測:因爲整個記錄點是定義中的字段順序並不重要。如果是這樣,你可以使用一個元組來代替。 (當然,您可能需要一個數據結構,其中的部分定義順序很重要,**和**允許您通過名稱訪問它們以方便起見。無論這是一個好主意還是值得費心添加另一個基礎雖然這樣的數據類型絕對不是爭論。) – millimoose

+8

我不會看到記錄作爲例外。 Haskell的打字一般是非常有名的,而不是結構性的。 – kosmikus

回答

8

Haskell有結構類型,而不是結構性的打字,這是不太可能發生改變。*

拒絕准許名義上不同,但結構上相似類型作爲參數的互換稱爲類型安全。這是一件好事。 Haskell甚至提供了一個新類型聲明來提供名義上不同的類型,從而允許您執行更多的類型安全。類型安全是一種簡單的方法,可以在早期捕獲錯誤,而不是在運行時允許錯誤。

除了amindfv的很好的答案,其中包括通過類型類的特設多態性(實際上是一個程序員聲明的功能等價),有參數多態,你允許絕對的任何類型的,所以[a]允許任何類型的列表,並BTree a允許任何類型在你的二叉樹中。

這給出了三個答案「這些類型是否可以互換?」。

  1. 否;程序員並沒有這麼說。
  2. 因爲程序員這麼說,等同於特定目的。
  3. 不關心 - 我可以對這個數據集合做同樣的事情,因爲它不使用數據本身的任何屬性。

沒有4:編譯器否決了程序員,因爲他們碰巧使用了幾個Ints和一個類似於其他函數的字符串。

*我說Haskell不太可能改變爲結構分型。有一些討論介紹某種形式的可擴展記錄,但沒有計劃使(Int,(Int,Int))(Int, Int, Int)Triple {one::Int, two::Int, three::Int}相同,與Triple2 {one2::Int, two2::Int, three2::Int}相同。

+3

當您連續寫了三篇冗長的評論時,您可以承認您可能正在回答。轉換爲答案。 –

+1

這三個答案是我讀過的單態和有界/參數多態的最佳口語描述。謝謝! – ftor

9

Haskell記錄並不比其他類型系統「不那麼結構化」。每種類型都是完全指定的,或者「特別模糊」(即用類型類定義)。

同時允許HRecHRec2f,你有兩個選擇:

代數類型:

在這裏,你定義HRecHRec2記錄,同時成爲HRec類型的一部分:

data HRec = HRec { x :: Int, y :: Bool } 
      | HRec2 { p :: Int, q :: Bool } 

foo :: HRec -> Bool 

(或者,也許更習慣:) :)

data HRecType = Type1 | Type2 
data HRec = HRec { hRecType :: HRecType, x :: Int, y :: Bool } 

類型類

在這裏,你定義foo爲能夠接受任何類型的輸入,只要一個類型類的實例已經爲該類型寫着:

data HRec = HRec { x :: Int, y :: Bool } 
data HRec2 = HRec2 { p :: Int, q :: Bool } 

class Flexible a where 
    foo :: a -> Bool 

instance Flexible HRec where 
    foo (HRec a _) = a == 5 -- or whatever 

instance Flexible HRec2 where 
    foo (HRec2 a _) = a == 5 

使用類型類可以比常規結構類型更進一步 - 您可以接受嵌入了必要信息的類型,前夕n對於類型不表面上看起來很相似,例如:

data Foo = Foo { a :: String, b :: Float } 
data Bar = Bar { c :: String, d :: Integer } 

class Thing a where 
    doAThing :: a -> Bool 

instance Thing Foo where 
    doAThing (Foo x y) = (x == "hi") && (y == 0) 

instance Thing Bar where 
    doAThing (Bar x y) = (x == "hi") && ((fromInteger y) == 0) 

我們可以運行fromInteger(或任意功能)離開我們有得到我們需要的數據!

+0

我不認爲這回答了這個問題。 – luqui

+1

@luqui - 回答這個問題,我認爲你需要說的是「haskell並沒有真正的結構化打字。」我添加了解決方案以顯示OP在haskell中獲得相同效果的慣用方法 – amindfv

0

我所知道的結構類型記錄的兩個庫實現在Haskell:

HList是年齡大了,在一篇優秀的論文解釋:Haskell的忽視對象系統(免費上網,但因此不會讓我包含更多鏈接)

vinyl是更新的,並使用奇特的新的GHC功能。至少有一個圖書館,vinyl-gl,正在使用它。

雖然我無法回答您的問題的語言設計部分。

+0

也有CTRex。 –

1

要回答你的最後一個問題,Go和Scala確實有結構類型。有些人(包括我)會稱之爲「靜態不安全的類型」,因爲它隱式地聲明程序中所有同名的方法具有相同的語義,這意味着「遠距離的幽靈行爲」,將源文件中的代碼與該程序從未見過的某個庫中的代碼。

IMO更好地要求相同名稱的方法明確聲明它們符合行爲的命名語義「模型」。

是,編譯器會保證該方法是可調用的,但它是不是更安全比說:

f :: [a] -> Int 

,讓編譯器來選擇任意的實現,可能會或可能不會length

(A類似的想法可以提出使用Scala「implicits」安全或哈斯克爾(GHC)「反思」包?)