۲۹ - ۵کمدقتیِ غیرقابل تحملِ try کردن
یه آزمایشِ کوچولوی دیگه انجام بدیم:
import Control.Exception
canICatch :: Exception e
=> e
-> IO (Either ArithException ())
canICatch e =
try $ throwIO e
اینجا throwIO
جدیده، تابعیه که میشه باهاش استثنا انداخت. چیزی که اینجا میخوایم نشون بدیم اینه که این عهدهگیرنده نمیتونه همهی تایپهای استثنا رو بگیره، پس ما هم از throwIO
استفاده میکنیم تا تایپهای مختلفِ استثنا رو بندازیم.
اینجا Left
فقط میتونه یه ArithException
رو بگیره یا مدیریت کنه، نه هیچ گونهی دیگهای رو. پس اگه یه تایپِ استثنا ِ دیگهای بندازیم، چنین چیزی میگیریم:
Prelude> canICatch DivideByZero
Left divide by zero
Prelude> canICatch StackOverflow
*** Exception: stack overflow
Prelude> :t DivideByZero
DivideByZero :: ArithException
Prelude> :t StackOverflow
StackOverflow :: AsyncException
حالتِ دوم از زیرِ دستِ try
در رفت، چون تلاشمون گرفتنِ یه ArithException
بود، نه یه AsyncException
.
چندین بار اشاره کردیم که SomeException
روی همهی تایپهایی که تایپکلاسِ Exception
دارن منطبق میشه، پس سعی کنین کُدِ بالا رو طوری بنویسین که StackOverflow
یا هر استثنا ِ دیگهای رو بگیره.
با یه برنامهای که انقدر اجرا میشه تا یه استثنا ِ مدیریتنشده جلوش رو بگیره، آزمایشمون رو ادامه میدیم:
module StoppingTheParty where
import Control.Concurrent (threadDelay)
import Control.Exception
import Control.Monad (forever)
import System.Random (randomRIO)
randomException :: IO ()
randomException = do
i <- randomRIO (1, 10 :: Int)
if i `elem` [1..9]
then throwIO DivideByZero
else throwIO StackOverflow
main :: IO ()
main = forever $ do
let tryS :: IO ()
-> IO (Either ArithException ())
tryS = try
_ <- tryS randomException
putStrLn "Live to loop another day!"
-- میکروثانیه
threadDelay (1 * 1000000)
-- ^--------^
-- م. تأخیرِ ریسهی پردازش
forever
رو قبلاً گفته بودیم؛ میذاره برنامه همینطور بینهایت اجرا بشه. threadDelay
رو اضافه کردیم تا حلقه آرومتر بشه و اتفاقاتی که میوفته رو بهتر بشه دید. دقت کنین واحد زمانیش به میکروثانیهست.
tryS
باعث میشه ArithException
ها به عهده گرفته بشن. اون استثناها کنار زده میشن و حلقه ادامه پیدا میکنه. بالاخره وقتی اون عددِ تصادفی ۱۰ بشه، بجای ArithException
، یه استثنا ِ AsyncException
انداخته میشه و برنامهمون به سرعت میمیره. سعی کنین کاری کنین هردوتا استثنا به عهده گرفته بشن و حلقه ِ برنامه هیچ وقت تموم نشه.