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