where
句は式でないため、print (x where x = 23 :: Int)
のような書き方はできません (parse error on input ‘where’
が発生します) 。
本記事では、where
句の書き方についてまとめます。
1. where
句を書ける場所
モジュール定義、クラス宣言およびインスタンス宣言を除くと、where
句を書ける場所は以下の 2 種類のみです:
- 関数定義を含む変数束縛
- すなわち
where
の左側に=
が必須
- すなわち
-
case
式の選択肢- すなわち
where
の左側に->
が必須
- すなわち
ちなみに無名関数では変数束縛しないため (\x -> x * y where y = 23 :: Int)
のような書き方はできません。
参考「4.4.3 Function and Pattern Bindings - 4 Declarations and Bindings」
参考「3.13 Case Expressions - 3 Expressions」
参考「10 Syntax Reference」
2. where
句の書き方
2.1. 基本
f :: Int -> Int
f x = y
where
y = x * 42
main :: IO ()
main = do
print $ f 23
data T = Foo | Bar
main :: IO ()
main = do
let x = Foo :: T
print $ case x of
Foo -> y where y = 23 :: Int
Bar -> y where y = 42 :: Int
2.2. ガードを用いる場合
複数のガードを付けている場合でも、1 つの変数束縛および case
式の 1 つの選択肢に対して 1 つの where
を使用することができます。
f :: Int -> Int
f x
| x >= 0 = y
| otherwise = - y
where
y = x * 42
main :: IO ()
main = do
print $ f 23
case
式の選択肢の場合でも変数束縛の場合と同様ですが、case
式内でガードを用いるとコードがややこしくなるため、そもそも関数を分ける等して case
式内でガードを用いない方が良いかもしれません。
main :: IO ()
main = do
let x = 23 :: Int
print $ case x of
y
| y >= 0 -> z
| otherwise -> - z
where
z = y * 42 :: Int
2.3. do
式内で where
句を書く場合
do
式に続けて where
を書くと do
式内でなく do
式外に書くのと同じ意味になります。
main :: IO ()
main = do
print x
where
x = 23 :: Int
main :: IO ()
main = f
where
f = do
print x
x = 23 :: Int
do
式内の let
による変数束縛で where
句を使用することで、do
式内で where
句を書くことができます。
main :: IO ()
main = do
let x = y * 42
where
y = 23 :: Int
print x
2.4. どうしても式内で where
句を書きたい場合
case () of _ ->
で始まる case
式を用いることで、式内で where
句を書くことができます。
main :: IO ()
main = do
print (case () of _ -> x where x = 23 :: Int)
print
$ (\x -> case () of _ -> x * y where y = 42 :: Int)
(23 :: Int)