インデントで悩まないための単純な指針

Haskellコードを書いていて、インデントを揃えるのが面倒だとか、インデントが揃っているか判別しにくいということがあるかもしれない。以前は私にもよくあったのだが、二つの簡単な指針に従うことに決めてからこの種の問題に悩まされることはなくなった。ので紹介する。

  1. インデントを揃える際は、そこより左には空白しか置かない
  2. インデントは常にkの倍数個の半角スペースで行う。ここでkはプロジェクトごとの定数(以下ではk=2)

具体例

foo x y =
  do runThis
     runThat

と書かずに、

foo x y = do
  runThis
  runThat

と書く。

foo = bar * 2
  where bar = 1 + quux
        quux = log 3

と書かずに、

foo = bar * 2
  where
    bar = 1 + quux
    quux = log 3

と書く。

data Foo a = Foo { fooId :: !Int
                 , fooName :: !String
                 , fooRef :: !(IORef a)
                 }

と書かずに、

data Foo a = Foo
  { fooId :: !Int
  , fooName :: !String
  , fooRef :: !(IORef a)
  }

と書く。

build = runBuilder $ fromInt foo
                     <> fromInt bar
                     <> fromString baz

と書かずに、

build = runBuilder $
  fromInt foo
     <> fromInt bar
     <> fromString baz

と書く。

何が良いか

行頭にスペース以外を置かないので、

  • 識別子の名前変更や、引数の追加/削除によってインデントを変更する必要がない
  • ほとんど必要最小限のインデント量になるので、コードが無駄に横に長くなりにくい。whereの三段ネストくらいなら平気でできる*1
  • Unicodeの記号を使ってもずれない。プロポーショナルフォントですら問題ない

常にkの倍数個のスペースでインデントするので、

  • インデント水準の変更が簡単*2
  • 異なるインデント水準は最低でもk桁違うので見分けやすい

何が悪いか

doの中でletを使うときに微妙に格好悪い。

do
  let
    foo = 1
    bar = 2
  go foo bar

以下のように書きたくなる。(とくにk=4の場合)

do
  let foo = 1
      bar = 2
  go foo bar

また、人によってはwhere節の内部がインデントされすぎると感じる。原則を曲げてwhereをk/2だけインデントする方が好きな人もいるかもしれない。

foo = bar * 2
 where
  bar = 1 + quux
  quux = log 3

*1:whereのネストは読み難いという人もいるみたいだけど

*2:vimなら範囲選択して>とか