インデントスタイル(またはレイアウトシステム)

入門Haskell」ではインデントスタイルについては,必要なときにその都度,といった感じでまとまった説明がなかった。

moiの頭の中 – 3.5 Functions(その3)

Haskellはコードを構築するのに「レイアウト」と呼ばれるシステムを用いる(プログラミング言語Pythonは似たシステムを用いている)。レイアウトシステムは、CやJavaのような他の言語が必要とする明示的なセミコロンや中括弧なしでコードを書くことができる。

moiの頭の中 – 3.5 Functions(その4)

レイアウトについての一般的な規則は、let、doそしてofキーワードの位置の次に開き中括弧が挿入され、次の命令が現れる桁位置が記憶されることである。それ以降、セミコロンが同じ量を字下する全ての行の前に追加される。次の行を字下げしないなら、閉じ中括弧が追加される。

つまり,let,do,of のあとに続く語とそれに続く行の先頭をそろえろってことだな。こんな風に。

f x = case x of 1 -> "one"
                2 -> "two"
                3 -> "three"
                _ -> "many"

中括弧やセミコロンが云々というのは,上のコードがこんな風に解釈されるってことか。

f x = case x of {1 -> "one";
                 2 -> "two";
                 3 -> "three";
                 _ -> "many"}

ようするに見やすく書けば問題なさそうだ。

ところで,if ~ then ~ else や where 節については書いてないがどうなんだろう。
まずはif ~ then ~ else から。いままで then,else は if よりも下げて書いてたけどおなじインデントでも大丈夫。

f x = if x > 0
      then "Positive"
      else "Negative or Zero"
*Main> f 0
"Negative or Zero"

if よりも前にあっても大丈夫のようだ。

f x = if x > 0
    then "Positive"
  else "Negative or Zero"
*Main> f 2
"Positive"

なら where 節は?

f x = map g x
  where g 0 = 1
        g 1 = 0
*Main> f [1,0,0,1,1,1]
[0,1,1,0,0,0]

こっち(↓)がダメなのは,関数(g)定義の先頭があってないからだろうな。

f x = map g x
  where g 0 = 1
      g 1 = 0
*Main> :l ind.hs
Compiling Main             ( ind.hs, interpreted )

ind.hs:14:8: parse error on input `g'

ついでにガード節。これも大丈夫なんだ。

f x | x < 0 = (-1) * x
  | x > 0 = 1 * x
 | otherwise = 0
*Main> f 3
3
*Main> f 0
0
*Main> f (-2)
2

まとめ。

  • let,do,of のあと(という中というか)は頭をそろえる。
  • 関数定義の頭はそろえる。
  • where 節やガード節はそろえなくても大丈夫(だけど見やすいようにそろえる)。