2011-03-20 132 views
41

許多人認爲Haskell的記錄語法是對其他語言優雅的疣,因爲它的醜陋語法和命名空間污染。另一方面,它通常比基於位置的替代方案更有用。Haskell記錄語法

而是像這樣的聲明:

data Foo = Foo { 
    fooID :: Int, 
    fooName :: String 
} deriving (Show) 

這在我看來,這些方針的東西會比較有吸引力:

data Foo = Foo id :: Int 
       name :: String 
       deriving (Show) 

我敢肯定,必須有一個很好的理由我錯過了,但爲什麼採用基於佈局的更清晰的C語言語法?

其次,有沒有什麼可以解決命名空間問題,所以我們可以在將來的Haskell版本中編寫id foo而不是fooID foo? (除了目前可用的基於longwinded類的解決方法之外)。

+14

的語法是好的 - 什麼是「疣」存在的事實,記錄是不可擴展的(人們希望更多的權力)和名字空間的問題更在於。正如我習慣了常規語法,其中一種情況是我更喜歡它佈局語法 - 也許沒有人考慮過Haskell設計時的佈局語法? 「基於類型的名稱解析」TBNR已被提出用於第二個問題 - 許多人似乎認爲它存在語義上的問題(這不利於該提案几乎沒有說服力的書寫),但GHC-HQ的一名成員似乎喜歡它,所以它可能會出現。 – 2011-03-20 08:41:41

+2

@Stephen Tetley:你爲什麼不把它作爲答案?這很棒! – fuz 2011-03-20 09:38:32

+2

在我上面的評論中,我的意思是TDNR - 'Type Directed Name Resolution'不幸在這種情況下Stack Overflow不允許我編輯評論。 @FUZxxl - 謝謝,但我認爲這是一個意見,因此它似乎是一個評論,而不是一個答案,它肯定不是普遍的觀點。 – 2011-03-20 11:24:49

回答

42

那麼如果沒有人會嘗試,那麼我會採取另一個(稍微更仔細研究)刺回答這些問題。

TL;博士

問題1:這只是骰子滾的方式。這是一個環境選擇,它卡住了。

問題2:是(sorta)。當然有幾個不同的方面正在考慮這個問題。

請仔細閱讀,以獲得對每個答案的非常長期的解釋,並基於我發現的相關和有趣的鏈接和引語。

爲什麼採用基於佈局的更清晰的C語言語法?

微軟研究人員寫了一個History of Haskell論文。第5.6節討論記錄。我還要舉第點點,這是有見地:

一位來自哈斯克爾 的早期版本最明顯的疏漏是沒有記錄的,提供名爲網絡的視場。鑑於 記錄在實踐中非常有用,它們爲什麼被省略?

的Microsofties然後回答自己的問題

最強的理由似乎是,沒有明顯的「恰到好處」的設計。

你可以自己閱讀這篇文章的細節,但他們說Haskell最終採用了記錄語法,因爲「數據結構中命名字段的壓力」。

由當時的哈斯克爾1.3設計正在進行中,在1993年,用戶 壓力在數據結構命名的網絡連接的視場爲強,因此該委員會最終採用了簡約的設計......

你問爲什麼這是爲什麼?那麼,據我所知,如果早期的Haskellers有他們的方式,我們可能從來沒有記錄語法。這個想法顯然已經被那些已經習慣了類C語法的人推到了Haskell上,並且更有興趣將類似C的東西變成Haskell,而不是「Haskell的方式」。 (是的,我知道這是一個非常主觀的解釋。我可能是完全錯誤的,但在沒有更好的答案,這是我可以得出的最佳結論。)

是否有管道什麼解決命名空間問題?

首先,不是每個人都覺得這是一個問題。幾個星期前,一位發燒友向我(以及其他人)解釋說,具有不同名稱的函數是一個壞主意,因爲它會使「名爲___的函數做什麼」的分析變得複雜。事實上,這不是一種功能,而是許多功能。這個想法對於Haskell來說可能會很麻煩,因爲它會使類型推斷變得複雜。

有輕微的切線,該Microsofties有有趣的事情談談Haskell的類型類:

這是時間的一個令人高興的巧合 是Wadler和Blott發生在剛剛的那一刻時,產生這種核心思想 語言設計仍在流行。

別忘了哈斯克爾還年輕一次。有些決定僅僅是因爲它們的制定而已。

不管怎麼說,有這個「問題」可以處理一些有趣的方法:

Type Directed Name Resolution,提議修改哈斯克爾(在評論上述)。只要閱讀該頁面即可看到它涉及該語言的很多領域。總而言之,這不是一個壞主意。已經考慮了很多想法,以便它不會與東西發生衝突。但是,它仍然需要更多的關注才能將其融入現在(更成熟)的Haskell語言中。

另一篇Microsoft文件OO Haskell特別提出了對Haskell語言的擴展以支持「ad hoc過載」。這很複雜,所以你只需要自己檢查第4部分。它的要點是自動(?)推斷「有」類型,並添加一個額外的步驟,類型檢查他們稱之爲「改進」,在下面的選擇性引用中模糊地概述:

鑑於類約束Has_m (Int -> C -> r)有 只有一個m匹配這個約束......因爲只有一個選擇,我們現在應該做出來,並且 將r修復爲Int。因此,我們得到預期的類型ff :: C -> Int -> IO Int ... [這]是一個簡單的 設計選擇,以及一個基於這樣的思想:Has_m關閉

道歉用於鬆散報價;如果這對你有所幫助,那麼很好,否則就去閱讀論文。這是一個複雜的(但令人信服的)想法。

Chris Done使用Template Haskell以與OO Haskell紙張類似的方式提供duck typing in Haskell(使用「Has」類型)。從他的網站有幾個交互式會話樣本:

λ> flap ^. donald 
*Flap flap flap* 
λ> flap ^. chris 
I'm flapping my arms! 

fly :: (Has Flap duck) => duck -> IO() 
fly duck = do go; go; go where go = flap ^. duck 

λ> fly donald 
*Flap flap flap* 
*Flap flap flap* 
*Flap flap flap* 

這需要一點點樣板/不尋常的語法,我個人寧願堅守類型類。但是對克里斯·多恩自由地發表他在該地區的踏實工作表示讚賞。

+4

爲哈斯克爾歷史鏈接+1 :) – 2011-04-02 03:25:35

+23

「微軟研究人員撰寫哈斯格爾歷史論文」聽起來有偏見。該論文由Haskell的四名設計師和創作者撰寫;而今天恰好如此,他們中的一人Simon Peyton Jones在微軟研究院工作(並在MSR網站上主持他的論文)。所以你認爲Haskell設計背後的人是「微軟」 - 我認爲這是一個有點貶義的詞。 – 2013-08-26 11:26:04

+0

@Joker_vD你知道你可以建議一個編輯權嗎?如果這是真的,我想看看它編輯。 – corazza 2016-01-02 16:09:02

5

這個答案只是我在這個問題上的一些隨機想法。我推薦我的另一個答案,因爲爲了這個答案,我花了很多時間去查閱和參考其他人的工作。

記錄語法

以在黑暗中的幾個刺:你的「佈局爲基礎」的提出語法看起來很像非記錄語法data聲明;這可能會引起混淆解析(?)

--record 
data Foo = Foo {i :: Int, s :: String} deriving (Show) 
--non-record 
data Foo = Foo Int String deriving (Show) 
--new-record 
data Foo = Foo i :: Int, s :: String deriving (Show) 

--record 
data LotsaInts = LI {a,b,c,i,j,k :: Int} 
--new-record 
data LostaInts = LI a,b,c,i,j,k :: Int 

在後一種情況下,究竟是什麼:: Int應用?整個數據聲明?

帶有記錄語法(當前)的聲明與構造和更新語法類似。對於這些情況,基於佈局的語法而不是更清晰;你如何解析那些額外的=標誌?

let f1 = Foo {s = "foo1", i = 1} 
let f2 = f1 {s = "foo2"} 

let f1 = Foo s = "foo1", i = "foo2" 
let f2 = f1 s = "foo2" 

你怎麼知道f1 s是一個記錄更新,而不是一個函數應用程序?

命名空間

如果你想交融的使用你的類定義與前奏的idid?你如何指定你正在使用哪一個?你能想到比合格進口和/或hiding關鍵字更好的方法嗎?

import Prelude hiding (id) 

data Foo = Foo {a,b,c,i,j,k :: Int, s :: String} 
       deriving (Show) 

id = i 

ghci> :l data.hs 
ghci> let foo = Foo 1 2 3 4 5 6 "foo" 
ghci> id foo 
4 
ghci> Prelude.id f1 
Foo {a = 1, b = 2, c = 3, i = 4, j = 5, k = 6, s = "foo"} 

這些都不是偉大的答案,但他們是我已經得到了最好。我個人不認爲記錄語法是醜。我確實覺得使用命名空間/模塊的東西還有改進的空間,但我不知道如何使它變得更好。

+0

感謝您的回覆,但FWIW我的佈局版本只是作爲一個示例,而不是一個應該這樣做的建議。我同意命名空間問題更重要 - 希望像@ stephen的TDNR這樣的東西能夠獲得一些吸引力。 – 2011-03-21 23:26:15

+0

可能是自動的/必要的限定條件,比如'data Foo = Foo {id :: Int}'和'Foo.id'?它使宣言簡潔明瞭,用法清晰。 – 2014-07-26 01:05:20

8

我只是想我會添加一個鏈接來解決命名空間問題。看來overloaded record fields for GHC即將在GHC 7.10(並且可能已經在HEAD中)使用OverloadedRecordFields extension

這將使語法如

data Person = Person { id :: Int, name :: String } 
data Company { name :: String, employees :: [Person] } 

companyNames :: Company -> [String] 
companyNames c = name c : map name (employees c) 
+0

只是一個附錄 - OverloadedRecordFields避免了Dan Burton的回答上面指出的關於類型推斷的問題,只允許它們用於已經可以清楚地推斷出類型的情況。在實踐中,這是大多數情況下(至少如果您遵循聲明頂級函數類型的常見習慣用法)。現在有擴展正在工作,擴展了它們可以用於類型推斷或多態的各種方式,包括一個由給定字段名稱的所有記錄實現的提議的自動實例化類型類。 – Jules 2017-07-15 15:10:08

+0

...這與Dan Burton的答案中引用的Chris Done的鴨式輸入模板Haskell有點類似,除了沒有任何需要使用Template Haskell和更直接的語法。 – Jules 2017-07-15 15:18:44