Haskell では以下の 3 種類の <-
があります:
-
do
記法 - リスト内包表記
- パターンガード
1. do
記法の <-
do
記法の <-
は演算子 =<<
および >>=
のような動作をします。
右辺が Monad m => m a
型のとき、左辺は a
型です。
main :: IO ()
main = do
do
x :: Int <- pure 23 :: IO Int
print x
print =<< (pure 23 :: IO Int)
23
23
参考「3.14 Do Expressions - 3 Expressions」
2. リスト内包表記の <-
リスト内包表記の <-
はリスト内の要素を表すような条件を意味し、「ジェネレータ」と呼ばれます。
右辺が [a]
型のとき、左辺は a
型です。
単純な例では map
関数のような動作をします。
リスト型はモナドのため、モナドの演算子や do
記法でも似たような書き方ができます。
main :: IO ()
main = do
--
print $ do
[x * 2 | x <- [1..3]] :: [Int]
--
print $ do
map (* 2) [1..3] :: [Int]
print $ do
(* 2) <$> [1..3] :: [Int]
print $ do
x <- [1..3]
pure $ x * 2 :: [Int]
[2,4,6]
[2,4,6]
[2,4,6]
[2,4,6]
参考「3.11 List Comprehensions - 3 Expressions」
3. パターンガードの <-
ガードの <-
はパターンや case
式の選択肢のような動作をし、「パターンガード」と呼ばれます。
右辺と左辺の型は等しくします。
data T = Foo | Bar
f :: T -> String
f x
| Foo <- x = "Foo"
| Bar <- x = "Bar"
g :: T -> String
g Foo = "Foo"
g Bar = "Bar"
main :: IO ()
main = do
let x = Foo :: T
--
putStrLn $ f x
putStrLn $ case x of
y
| Foo <- y -> "Foo"
| Bar <- y -> "Bar"
--
putStrLn $ g x
putStrLn $ case x of
Foo -> "Foo"
Bar -> "Bar"
Foo
Foo
Foo
Foo
パターンガードを用いた変数束縛も可能です。
data T = Foo Int | Bar
f :: T -> Int
f x
| Foo y <- x, y > 0 = y
| otherwise = 0
g :: T -> Int
g (Foo x)
| x > 0 = x
| otherwise = 0
g Bar = 0
main :: IO ()
main = do
let x = Foo 23 :: T
--
print $ f x
print $ case x of
y
| Foo z <- y, z > 0 -> z
| otherwise -> 0
--
print $ g x
print $ case x of
Foo y
| y > 0 -> y
| otherwise -> 0
Bar -> 0
23
23
23
23
参考「4.4.3 Function and Pattern Bindings - 4 Declarations and Bindings」
参考「3.13 Case Expressions - 3 Expressions」