Навеяно темой
"Конструкция AND THEN?".
Илья Ермаков писал(а):
В ряде задач нужно ещё различать, на каком этапе неуспех. Но это делается явной переменной, хранящей текущий этап.
Код:
step := 1;
Первый_этап;
IF первый этап удался THEN
step := 2;
Второй этап;
AND второй этап удался THEN
...
ELSE
Log.String("Ошибка на этапе "); Log.Int(step)
END
По аналогии с монадой Maybe делаем новый тип данных и прикручиваем к нему монаду:
Код:
data AndThen a = AndThen Int (Maybe a)
instance Monad AndThen where
return a = AndThen 0 (Just a)
fail _ = AndThen 0 Nothing
(AndThen x Nothing) >>= _ = AndThen x Nothing
(AndThen x (Just y)) >>= f = f y
calcAndThen x done failed =
case x of
AndThen _ (Just a) -> done a
AndThen step Nothing -> failed step
Выполняемые (вычисляемые) шаги оформляются как "AndThen номер_шага вычисление". Вычисление должно выдать "Nothing" в случае неуспеха или "Just значение" в случае успеха.
Функция calcAndThen вычисляет цепочку шагов, помещённых в блок do, в случае успеха всех шагов вычисляет над результатом функцию done, в случае неуспеха -- вычисляет ф-цию failed над шагом, в котором произошёл сбой.
Тест:
Код:
main = do
calcAndThen
(do a <- AndThen 1 (Just 10)
b <- AndThen 2 (Just 20)
c <- AndThen 3 (Just 30)
return $ a + b + c
)
(\x -> putStrLn $ "Result = " ++ show x)
(\y -> putStrLn $ "Error on step " ++ show y)
Здесь все шаги успешны и результат:
Код:
Result = 60
А здесь в одном из шагов (во втором) -- сбой:
Код:
main = do
calcAndThen
(do a <- AndThen 1 (Just 10)
b <- AndThen 2 Nothing
c <- AndThen 3 (Just 30)
return $ a + b + c
)
(\x -> putStrLn $ "Result = " ++ show x)
(\y -> putStrLn $ "Error on step " ++ show y)
и результат:
Код:
Error on step 2
Не хватает синтаксического сахара, поэтому не очень наглядно. Надо подумать ещё.