Haskell/縮排
Haskell 依靠縮排來減少程式碼的冗長。儘管在實踐中有一些複雜性,但實際上只有幾個基本的佈局規則。[1]
屬於某個表示式的一部分的程式碼應該比該表示式的開頭縮排更多(即使該表示式不是該行的最左側元素)。
最簡單的例子是 'let' 繫結組。繫結變數的等式是 'let' 表示式的一部分,因此應該比繫結組的開頭縮排更多:'let' 關鍵字。當你在單獨的行上開始表示式時,你只需要縮排一個空格(儘管多個空格也是可以接受的,並且可能更清晰)。
let
x = a
y = b
你也可以將第一個子句與 'let' 放在一起,只要你將其他子句縮排對齊。
| 錯誤 | 錯誤 | 正確 |
|---|---|---|
let x = a
y = b
|
let x = a
y = b
|
let x = a
y = b
|
這往往會讓很多初學者感到困惑:所有分組的表示式必須完全對齊。在第一行,Haskell 將表示式左側的所有內容都算作縮排,即使它不是空格。
以下是一些更多示例
do
foo
bar
baz
do foo
bar
baz
where x = a
y = b
case x of
p -> foo
p' -> baz
請注意,對於 'case',將第一個子表示式放在與 'case' 關鍵字相同的行上並不常見(儘管它仍然是有效的程式碼)。因此,case 表示式中的子表示式往往只比 'case' 行縮排一個步驟。另請注意我們是如何將箭頭對齊的:這純粹是美觀的,不算是不同的佈局;只有縮排(即從最左側邊緣開始的空格)會影響佈局的解釋。
當表示式的開頭不在行的開頭時,事情會變得更加複雜。在這種情況下,只需比包含表示式開頭的行縮排更多即可。在以下示例中,do 位於行的末尾,因此表示式的後續部分只需相對於包含do 的行縮排,而不是相對於do 本身。
myFunction firstArgument secondArgument = do
foo
bar
baz
以下是一些可行的替代佈局
myFunction firstArgument secondArgument =
do foo
bar
baz
myFunction firstArgument secondArgument = do foo
bar
baz
myFunction firstArgument secondArgument =
do
foo
bar
baz
如果你使用分號和花括號來進行分組和分隔,就像在 C 這樣的“一維”語言中一樣,實際上可以選擇不使用縮排。即使 Haskell 程式設計師普遍認為有意義的縮排可以使程式碼更易讀,但瞭解如何從一種風格轉換為另一種風格可以幫助你理解縮排規則。整個佈局過程可以用三個翻譯規則(加上一個不常用的第四個規則)概括起來。
- 如果你看到一個佈局關鍵字(
let、where、of、do),就在它後面的東西之前插入一個左花括號。 - 如果你看到一些縮排到相同級別的程式碼,就插入一個分號。
- 如果你看到一些縮排到更低級別的程式碼,就插入一個右花括號。
- 如果你在列表中看到一些意外的東西,比如
where,就在分號之前插入一個右花括號。
例如,這個定義...
foo :: Double -> Double
foo x =
let s = sin x
c = cos x
in 2 * s * c
...可以不考慮縮排規則而重寫為
foo :: Double -> Double;
foo x = let {
s = sin x;
c = cos x;
} in 2 * s * c
在 GHCi 中編寫單行程式碼時,顯式使用花括號和分號可能很方便。
Prelude> let foo :: Double -> Double; foo x = let { s = sin x; c = cos x } in 2 * s * c
| 練習 |
|---|
|
使用顯式花括號和分號重寫控制結構章節中的這段程式碼。 doGuessing num = do
putStrLn "Enter your guess:"
guess <- getLine
case compare (read guess) num of
LT -> do putStrLn "Too low!"
doGuessing num
GT -> do putStrLn "Too high!"
doGuessing num
EQ -> putStrLn "You Win!"
|
| 錯誤 | 錯誤 | 正確 | 正確 |
|---|---|---|---|
do first thing
second thing
third thing
|
do first thing
second thing
third thing
|
do first thing
second thing
third thing
|
do
first thing
second thing
third thing
|
由於上述“縮排的黃金法則”,do 塊中的花括號不是取決於do 本身,而是取決於緊隨其後的東西。例如,這段看起來很奇怪的程式碼塊是完全可以接受的。
do
first thing
second thing
third thing
因此,你也可以這樣編寫 if/do 組合
| 錯誤 | 正確 | 正確 |
|---|---|---|
if foo
then do first thing
second thing
third thing
else do something_else
|
if foo
then do first thing
second thing
third thing
else do something_else
|
if foo
then do
first thing
second thing
third thing
else do
something_else
|
這不是關於do,而是關於將do 內所有位於相同級別的專案對齊。
因此,以下所有內容都是可以接受的。
main = do
first thing
second thing
或
main =
do
first thing
second thing
或
main =
do first thing
second thing
註釋
- ↑ 參見 Haskell 報告(詞法單元) 的第 2.7 節關於佈局的內容。