Either
型から IO
型へ直接変換する関数は標準では提供されないため、either
関数を用いて変換します。
IO
型から Either
型へ変換するには try
関数または tryJust
関数を用います。
--
either error pure :: Either String a -> IO a
either errorWithoutStackTrace pure :: Either String a -> IO a
either throwIO pure :: Exception e => Either e a -> IO a
--
try :: Exception e => IO a -> IO (Either e a)
tryJust :: Exception e => (e -> Maybe b) -> IO a -> IO (Either b a)
参考「either - Data.Either」
参考「try - Control.Exception」
参考「tryJust - Control.Exception」
モナドの計算を中断する方法については別記事にしています。
参考「[Haskell] モナドの計算を中断する - Qiita」
1. Either a b -> IO b
値が Left
であれば例外を投げ、値が Right
であれば中身の値を IO
型に入れます。
(本記事では深く触れませんが、値が Left
のときに例外を投げずデフォルト値に置き換えたい場合は fromRight
関数を用いて Either a b -> b
の変換をします。)
1.1. Either String a -> IO a
either error pure
または either errorWithoutStackTrace pure
とすることで Either String a -> IO a
の変換を行えます。
import Control.Exception (catch, ErrorCall)
import System.IO (hPrint, stderr)
main :: IO ()
main = do
--
do
let x = Right 23 :: Either String Int
y :: Int <- either error pure x :: IO Int
print y
`catch` \e -> do
hPrint stderr (e :: ErrorCall)
do
let x = Left "Error" :: Either String Int
y :: Int <- either error pure x :: IO Int
print y
`catch` \e -> do
hPrint stderr (e :: ErrorCall)
--
do
let x = Right 23 :: Either String Int
y :: Int <- either errorWithoutStackTrace pure x :: IO Int
print y
`catch` \e -> do
hPrint stderr (e :: ErrorCall)
do
let x = Left "Error" :: Either String Int
y :: Int <- either errorWithoutStackTrace pure x :: IO Int
print y
`catch` \e -> do
hPrint stderr (e :: ErrorCall)
1.2. Exception e => Either e a -> IO a
either throwIO pure
とすることで Exception e => Either e a -> IO a
の変換を行えます。
import Control.Exception (catch, throwIO)
import System.IO (hPrint, stderr)
main :: IO ()
main = do
do
let x = Right 23 :: Either IOError Int
y :: Int <- either throwIO pure x :: IO Int
print y
`catch` \e -> do
hPrint stderr (e :: IOError)
do
let x = Left $ userError "Error" :: Either IOError Int
y :: Int <- either throwIO pure x :: IO Int
print y
`catch` \e -> do
hPrint stderr (e :: IOError)
1.3. その他
その他の Either a b
型の場合は a
型の値を String
または Exception e => e
型に変換し、前述の方法を用いて IO b
型にします。
import Control.Exception (catch, ErrorCall)
import System.IO (hPrint, stderr)
f :: Int -> IO Int
f x = do
error $ "Error: " ++ show x
main :: IO ()
main = do
do
let x = Right 23 :: Either Int Int
y :: Int <- either f pure x :: IO Int
print y
`catch` \e -> do
hPrint stderr (e :: ErrorCall)
do
let x = Left 42 :: Either Int Int
y :: Int <- either f pure x :: IO Int
print y
`catch` \e -> do
hPrint stderr (e :: ErrorCall)
2. IO a -> IO (Either b a)
2.1. Exception e => IO a -> IO (Either e a)
try
関数を用いると、例外を投げられていれば Left
の値を返し、そうでなければ Right
の値を返します。
import Control.Exception (ErrorCall, throwIO, try)
main :: IO ()
main = do
--
do
x :: Either ErrorCall Int <- try $ do
pure 23 :: IO Int
print x
do
x :: Either ErrorCall Int <- try $ do
error "Error" :: IO Int
print x
do
x :: Either ErrorCall Int <- try $ do
errorWithoutStackTrace "Error" :: IO Int
print x
--
do
x :: Either IOError Int <- try $ do
pure 23 :: IO Int
print x
do
x :: Either IOError Int <- try $ do
throwIO $ userError "Error" :: IO Int
print x
2.2. Exception e => (e -> Maybe b) -> IO a -> IO (Either b a)
tryJust
関数も try
関数と同様ですが、例外を投げられていれば他の型に変換してから Left
の値を返します。
例外が投げられていなければ try
関数と同様にそのまま Right
の値を返します。
(tryJust
関数は他の使い方がありますが、本記事では不説明。)
import Control.Exception (ErrorCall, throwIO, tryJust)
main :: IO ()
main = do
--
do
x :: Either String Int <- tryJust
(\e -> pure $ show (e :: ErrorCall))
$ do
pure 23 :: IO Int
print x
do
x :: Either String Int <- tryJust
(\e -> pure $ show (e :: ErrorCall))
$ do
errorWithoutStackTrace "Error" :: IO Int
print x
--
do
x :: Either String Int <- tryJust
(\e -> pure $ show (e :: IOError))
$ do
pure 23 :: IO Int
print x
do
x :: Either String Int <- tryJust
(\e -> pure $ show (e :: IOError))
$ do
throwIO $ userError "Error" :: IO Int
print x