LoginSignup
13
10

More than 5 years have passed since last update.

Haskellの(>>)ってもしかしてすごい便利じゃない?

Last updated at Posted at 2016-08-26

Haskellの(>>)ってもしかしてすごい便利じゃない?

(>>) :: Monad m => m a -> m b -> m b
  • 今までの印象
    • 型からして明らかに常に右を取る
    • do式ののりづけ関数
  • 今回気づいたこと
    • 値の世界について言及されていないから、左の値を取ることがある
      • m >> n = nといった法則は要求されてない

事の発端

 事の発端はMonadThrow(>>)の要請するこの法則を見た時に気づきを得た。

throwM x >> y = throwM x

MaybeEither eMonadThrowインスタンスなので、上記の法則を満たすっぽい!

例えばMaybeはこう

Nothing >> Just 10 = Nothing

Eitherはこう。

Left "error" >> Right 10 = Left "error"

これってすごい便利じゃない?

活用する

hoge :: IO a  -- 例外を発する可能性がある
foo  :: IO b  -- 例外を発する可能性がある
bar  :: IO c  -- 例外を発する可能性がある

このような関数があった時、こんなmainは嫌だよね!! X(

main :: IO ()
main = do
  x <- try hoge
  y <- try foo
  z <- try bar
  -- いずれかで例外が発生していればプログラムを終了したい
  case x of
    Left  e -> print (e :: SomeException)
    Right _ ->
      case y of
        Left  e' -> print (e' :: SomeException)
        Right _  ->
          case z of
            Left  e'' -> print (e'' :: SomeException)
            Right _   -> putStrLn "The program is succeed"

こうする。

main :: IO ()
main = do
  x <- try hoge
  y <- try foo
  z <- try bar
  -- いずれかで例外が発生していればプログラムを終了したい
  let a = x >> y >> z
  case a of
    Left e  -> print (e :: SomeException)
    Right _ -> putStrLn "The program is succeed"

これ

x >> y >> z

は、単なるこんな感じのintegrate関数の略記バージョンだ! :D

integrate :: Either e a1 -> Either e a2 -> Either e a3 -> Either e a3
integrate e1 e2 e3 = do
  x <- e1
  y <- e2
  z <- e3
  return z

実際に試す用のコードを載っけておくね。

import Control.Monad.Catch (try, SomeException)

hoge :: IO Int  -- 例外を発する可能性がある
hoge = return 10
foo  :: IO Char  -- 例外を発する可能性がある
foo = fail "foo is failed"
bar  :: IO Bool  -- 例外を発する可能性がある
bar = return True

main :: IO ()
main = do
  x <- try hoge
  y <- try foo
  z <- try bar
  -- いずれかで例外が発生していればプログラムを終了したい
  let a = x >> y >> z
  case a of
    Left e  -> print (e :: SomeException)
    Right _ -> putStrLn "The program is succeed"

応用

 こんなこともできる :D

firstLeftOrLastRight :: [Either e a] -> Either e a
firstLeftOrLastRight = foldr1 (>>)

main :: IO ()
main = do
  let rights   = [Right 1, Right 2, Right 3, Right 4] :: [Either String Int]
  let someLeft = [Right 1, Right 2, Left "oops!", Right 4]
  print $ foldr1 (>>) rights
  print $ foldr1 (>>) someLeft

便利!!

13
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
10