我想知道什么時候應該使用制表符,什么時候應該使用空格?特別是在守衛方面,我正在通過他向你學習一本 Haskell 的書,它說我應該總是使用空格。不過,這本書本身似乎在定義中使用了 4 個空格和警衛。例如這個函式:
replicate' :: (Num i, Ord i) => i -> a -> [a]
replicate' n x
| n <= 0 = []
| otherwise = x:replicate' (n-1) x
當我用一個空格替換 4 個空格/制表符時,在這種otherwise情況下會出現縮進/遺漏括號錯誤。但是,如果我使用制表符或 4 個空格,則可以。我對在制表符上使用空格有誤解嗎?每次應該是4個空格嗎?因為通常 1 個空格確實有效,所以只有守衛 ghci 幾乎總是(令人發指地并非總是)在這里抱怨。
順便說一句,我正在使用 sublime,以防出現問題。
提前非常感謝。
例如:
maximum' [] = error "maximum of empty list"
maximum' [x] = x
maximum' (x:xs)
| x > maxTail = x
| otherwise = maxTail
where maxTail = maximum' xs
引發縮進錯誤
uj5u.com熱心網友回復:
聽起來 OP 的實際問題是特定檔案中的一個奇怪狀態,但我想我會在這里提供一般問題的答案。
Haskell 語法的大多數部分對縮進完全不敏感(大多數關于布局 Haskell 代碼的常見做法是風格化的,而不是必要的)。例如,在 OP 的示例中撰寫最后一個方程的所有這些方法都可以正常作業:
-- guards indented more than where
maximum' (x:xs)
| x > maxTail = x
| otherwise = maxTail
where maxTail = maximum' xs
-- where indented more than guards
maximum' (x:xs)
| x > maxTail = x
| otherwise = maxTail
where maxTail = maximum' xs
-- all on one line, no indentation at all!
maximum' (x:xs) | x > maxTail = x | otherwise = maxTail where maxTail = maximum' xs
甚至像這樣可怕的東西也有效:
-- please, no
maximum' (x:xs) |
x
> maxTail = x
| otherwise
= maxTail where
maxTail
= maximum' xs
在顯示的代碼中,您可以做兩件事來搞亂縮進:
- 使用多行來定義等式,且任何續行不以至少一個空格字符開頭
- 使用多行來定義
where子句,任何續行都從小于where關鍵字后第一個字符的字符位置開始(即minmaxTail)
否則,此示例中的空格根本無關緊要(除了分隔識別符號和關鍵字)。
在 Haskell 中,縮進的重要性基本上只有一種通用方式。實際上,重要的不是縮進,而是對齊。這發生在包含可變數量條目的“塊”的背景關系中:
let <decls> in <expr>運算式在<decls>部分中包含 1個或多個宣告- 一個
where子句引入 1 個或多個宣告 instance定義的部分where有零個或多個方法定義- 一個
do塊有 1 個或多個陳述句 - 一個
case運算式有 1 個或多個案例(零個或多個帶EmptyCase擴展名) - 等等等等
這些塊中可變數量的條目是對齊重要的唯一地方。總有一個關鍵字介紹塊,塊中第一個條目的字符位置設定對齊;之后,恰好在該字符位置開始的每一行都被視為塊中下一個條目的開頭,超過該位置開始的每一行都被視為前一個條目的續行,并且在對齊之前開始的第一行position 被視為塊的結束(并且該行的內容不是塊的一部分)。有時還有一個關鍵字將指示塊的結尾,而不管任何縮進(例如,in部分let <decls> in <expr>由in關鍵字,即使它與部分或全部<decls>) 位于同一行。
順便說一句,此時您可能想知道為什么會出現這樣的代碼錯誤:
bar x y
= x y
我沒有使用上面的任何where, let, etc 塊,但是通過在bar沒有縮進的情況下將定義繼續到新行可能會出現對齊錯誤?我不是保證縮進只在塊中起作用嗎?好吧,實際上一個模塊的整個全域范圍是一個對齊的塊!我們通常不會注意到它,因為該塊通常使用對齊位置 0。但從技術上講,這就是正在發生的事情(因此,對于從對齊 0 開始的全域塊中的宣告之一,您不能有續行)。
這種基于對齊而不是縮進的布局是為什么標簽通常被認為難以用于布局 Haskell 代碼的原因。例如,考慮一下:
foo x y z = xy yz
where xy = x * y
yz = y * z
在這里,我使用了 4 個空格來縮進where部分,這是空格完全不相關的地方之一,所以我可以使用任何我喜歡的東西。因此,如果我習慣于在其他編程語言中使用制表符作為縮進,我可能會傾向于使用制表符而不是 4 個空格。
事情變得令人討厭的是,該yx = y * z行的正確縮進不是“2個縮進級別”,而是“與xy = x * y定義完全對齊”。因此,如果我使用制表符來縮進where,那么縮進下一行的唯一正確方法是使用制表符后跟 6 個空格。根據我的經驗,即使是智能格式化代碼編輯器也無法做到這一點(更不用說人工手動完成了);如果我的視圖設定有一個選項卡占用的空間比where關鍵字少(例如常見的 4 個空格),我將獲得至少 2 個前導選項卡,然后有足夠的空格使yz = y * z行看起來對齊與上面的定義。
根據規范,Haskell 編譯器將制表位視為相隔八個空格。所以我上面描述的情況(其中第一個定義where是 1 個制表符加 6 個普通字符,第二個定義是 2 個制表符加 2 個普通字符)會導致不可見的錯誤。編譯器認為這些定義位于位置 14 和 18,但對我來說它們看起來相同。這種排序問題并不好玩。因此,受到好評的評論“何時使用標簽?從不!這很容易。”
從技術上講,您可以將編輯器設定為在 8 個空格處顯示制表符停止,然后給定數量的縮進是所有空格還是制表符和空格的任何混合看起來都無關緊要。但是,大多數人不喜歡將他們的編輯器設定為將制表符設定為 8 個空格,并且修復任何特定數字會破壞使用制表符縮進的全部意義(每個用戶都可以配置“縮進級別”的視覺外觀)在他們的編輯器中獨立)。
也可以采用避免該問題的代碼風格。基本上:總是在關鍵字引入塊之后立即結束該行,以便該塊從新行開始(您可以提升下一個縮進級別)。然后你會寫(對于 OP 的例子):
maximum' (x:xs)
| x > maxTail = x
| otherwise = maxTail
where
maxTail = maximum' xs
如果您這樣做,那么您的對齊位置將始終是精確數量的制表符和零個正常字符,因此您最終不會被迫使用制表符和空格混合的前導空格。事實上,Haskell 的對齊規則變得非常類似于 Python 的縮進規則,如果你這樣編碼(它們不同的主要原因是 Haskell 允許你在與前面的代碼相同的行開始一個對齊的塊,而 Python 的塊總是前面有一個以冒號結尾的行)。
但到目前為止,在 Haskell 中使用制表符最常見的方法是:干脆不要這樣做。如果您愿意,請配置您的編輯器以在您按 Tab 鍵時插入空格直到下一個“制表位”。但請確保物理源代碼檔案用空格保存。
免費的肥皂盒時間!
就我個人而言,上述原因是我不喜歡在任何語言中使用制表符的原因。因為遲早會有人最終想要使一行上的某些內容在視覺上與另一行上的某些內容對齊,而這通常需要縮進,即制表符和空格的混合。編輯器幾乎永遠不會正確處理制表符和空格的組合(這樣做通常要求編輯器能夠在編碼器完成輸入之前判斷一行是續行還是新句法結構的開始,這充其量是依賴于語言的,最壞的情況是不可能的)。因此,一旦有人使用不同于他們使用的制表符寬度首選項,他們就會撰寫格式不正確的代碼。
一個例子是這個相當常見的布局(沒有特定的語言):
class Foo {
public int foo(int x, char y, long listOfParameters,
bool z, double ooopsRanOutOfLetters) {
codeStartsHere();
如果縮進級別是制表符,則引數串列延續的正確縮進是 1 個制表符和 15 個空格,但有人可能會得到 4 個制表符和 3 個空格,這會在任何其他制表符寬度處完全放棄對齊環境。基本上,如果要為每個編碼人員的偏好配置縮進級別(通過設定制表符寬度),那么插入縮進級別和插入視覺等效數量的空格之間存在根本區別,需要您考慮您使用哪個每次按 Tab 鍵時都打算這樣做。即使格式化純粹是對人類讀者的視覺幫助,并且不會改變編譯器/解釋器閱讀代碼的方式,但幫助人類讀者可以說比僅僅撰寫機器可以接受的東西更重要。
再一次,這個問題可以通過嚴格遵守精心構建的風格指南來解決,以避免發生上述布局。但我只是不想在設計或評估樣式指南時考慮這一點,也不想在撰寫代碼時考慮這一點。“始終使用空格縮進”是一個非常簡單的規則,可以放在樣式指南中,然后無論您采用其他規則如何(并且無論這些其他規則是否被嚴格遵循或有例外),它都不是問題。
uj5u.com熱心網友回復:
只使用空格,因為 Haskell 對縮進敏感,并且隱式布局塊必須從大于其布局關鍵字的列開始,因此準確跟蹤列很重要。
此外,根據 Haskell2010 ,制表位相隔 8 列,按照今天的縮進標準(通常最多 4 個空格),這是巨大的。
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/495986.html
標籤:哈斯克尔
上一篇:如何在GHCi中使用模式匹配?
下一篇:`NS`型別的大小寫匹配
