Навеяно темой"Конструкция AND THEN?".
> -- Илья Ермаков писал(а):
> В ряде задач нужно ещё различать, на каком этапе неуспех. Но это делается явной переменной, хранящей текущий этап.
По аналогии с монадой 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
```

Не хватает синтаксического сахара, поэтому не очень наглядно. Надо подумать ещё.