インデントおよび改行に関するスタイルガイドの例です。
主に以下のスタイルガイドを参考にしました。
(※完全な準拠はしていません。)
参考「Haskell Style Guide :: Kowainik」
1. 前提
なるべく if-then-else でなくガードを用います。
f :: Int -> Int
f x =
if x > 0
then 23 * x
else 0
f :: Int -> Int
f x
| x > 0 = 23 * x
| otherwise = 0
do 記法等を除いて、なるべく let 式でなく where 句を用います。
※ where 句は式でないため、関数定義を含む変数束縛で使用する必要があります。
参考「[Haskell] where 句は式でない - Qiita」
f :: Int -> Int
f x =
let y = 23 * x
in y
f :: Int -> Int
f x = y
where
y = 23 * x
g :: Int -> IO ()
g x = do
let y = 23 * x
print y
do 記法の let は変数ごとに付けます。
main :: IO ()
main = do
let x = 23 :: Int
y = 42 :: Int
print $ x * y
main :: IO ()
main = do
let x = 23 :: Int
let y = 42 :: Int
print $ x * y
case 式の選択肢における -> の右側のコードは、関数定義を含む変数束縛を用いて分離し、小さくします。
data T = Foo Int | Bar
f :: T -> Int
f x = case x of
Foo y
| y > 0 -> 23 * y
| otherwise -> 0
Bar -> 0
g :: T -> IO ()
g x = case x of
Foo y -> do
putStr "Foo: "
print $ 23 * y
Bar -> pure ()
data T = Foo Int | Bar
f' :: Int -> Int
f' x
| x > 0 = 23 * x
| otherwise = 0
f :: T -> Int
f x = case x of
Foo y -> f' y
Bar -> 0
g' :: Int -> IO ()
g' x = do
putStr "Foo: "
print $ 23 * x
g :: T -> IO ()
g x = case x of
Foo y -> g' y
Bar -> pure ()
2. インデント
基本はスペース 4 つずつでインデントします。
data T = Foo | Bar
list :: [Int]
list =
[ 10
, 20
, 30
]
f :: Int -> Int
f x
| x > 0 = x * 42
| otherwise = 0
main :: IO ()
main = do
print $ f
23
print $ do
Just 23 :: Maybe Int
let x = Foo :: T
putStrLn $ case x of
Foo -> "Foo"
Bar -> "Bar"
--
print list
ただし、以下の場合はスペース 2 つにします:
- 一部の
where句- 関数定義を含む変数束縛
-
`catch`の前で改行する場合 - 一部の
=- 関数定義かつそれぞれの引数で改行したい場合
f :: Int -> Int
f x = y
where
y = 23 * x
import Control.Exception (catch, ErrorCall)
import System.IO (hPrint, stderr)
main :: IO ()
main = do
do
errorWithoutStackTrace "Error"
`catch` \e -> do
hPrint stderr (e :: ErrorCall)
f :: Int -> Int -> Int
f
x
y
= x * y
g :: Int -> Int -> IO ()
g
x
y
= do
print $ x * y
do 記法の let では変数名の位置を基準にインデントします。
data T = Foo | Bar
main :: IO ()
main = do
let list =
[ 10
, 20
, 30
]
:: [Int]
let x = 23 :: Int
let y
| x > 0 = x * 42
| otherwise = 0
let z = z'
where
z' = y - 1729
let w = do
Just 23 :: Maybe Int
let v = Foo :: T
let u = case v of
Foo -> "Foo"
Bar -> "Bar"
--
print list
print z
print w
print u
3. 改行
以下の場合は必ず前後で改行します:
- 一部の
where句- 関数定義を含む変数束縛
f :: Int -> Int
f x = y where y = 23 * x
g :: Int -> Int
g x = y
where y = 23 * x
g' :: Int -> IO ()
g' x = do
print y
where y = 23 * x
h :: Int -> Int
h x = y where
y = 23 * x
f :: Int -> Int
f x = y
where
y = 23 * x
f' :: Int -> IO ()
f' x = do
print y
where
y = 23 * x
以下の場合は必ず後で改行します:
- 一部の
where句- モジュール定義
- クラス宣言
- インスタンス宣言
- レイアウトを用いた
do記法
module Foo where
class Bar a where
bar :: a -> a
instance Bar Int where
bar = (23 *)
f :: Int -> IO ()
f x = do putStr "Foo: "
print x
f :: Int -> IO ()
f x = do
putStr "Foo: "
print x
以下の場合は必ず前で改行します:
- 一部の
=- 関数定義かつそれぞれの引数で改行したい場合
f :: Int -> Int -> Int
f
x
y = x * y
g :: Int -> Int -> IO ()
g
x
y = do
print $ x * y
f :: Int -> Int -> Int
f
x
y
= x * y
g :: Int -> Int -> IO ()
g
x
y
= do
print $ x * y
演算子等があるところで改行したい場合、基本は演算子等の後でなく前で改行します。
data T = Foo |
Bar
list :: [Int]
list = [
10,
20,
30
]
f :: Int -> Int -> Int
f = (*)
main :: IO ()
main = do
print $
f 23 42
print $ f <$>
Just 23 <*>
Just 42
--
print list
let x = Foo :: T
putStrLn $ case x of
Foo -> "Foo"
Bar -> "Bar"
data T
= Foo
| Bar
list :: [Int]
list =
[ 10
, 20
, 30
]
f :: Int -> Int -> Int
f = (*)
main :: IO ()
main = do
print
$ f 23 42
print $ f
<$> Just 23
<*> Just 42
--
print list
let x = Foo :: T
putStrLn $ case x of
Foo -> "Foo"
Bar -> "Bar"
ただし、以下の場合は演算子の後で改行しても良いです:
- 一部の
=- 関数定義を含む変数束縛
- 一部の
->- 無名関数
※関数定義を含む変数束縛の = do や無名関数の -> do では間で改行しません。
※ case 式の選択肢における -> の前後では改行しません。
import Data.Foldable (for_)
list :: [Int]
list =
[ 10
, 20
, 30
]
f :: Int -> IO ()
f x = do
print x
main :: IO ()
main = do
print
$ (\ (x :: Int) ->
[ 10 * x
, 20 * x
, 30 * x
]
)
23
for_ [1..3] $ \ (x :: Int) -> do
print x
--
print list
f 23