Здравствуйте, Shmj, Вы писали:
S> для облегчения написания/поддержки кода?
Ну когда на хаскеле пишешь, они повсеместно, просто потому что это основной способ написания кода, который меняет какое-то состояние, бросает ошибки и делает ввод-вывод. Это как прозой говорить.
А из более интересных применений, недавно на работе писал парсер с использованием библиотеки монадных парсер-комбинаторов megaparsec, там код выглядел так:
pLam = do params <- pParamDefs
kw "=>"
(ty, exp) <- try pTypedExpr <|> pUntyped pExpr
return $ Lam params ty exp
pTypedExpr = do
ty <- pType
kw ":"
exp <- pExpr
return (Just ty, exp)
pAssign = do
(ty,name) <- pPossiblyTypedName
kw "="
exp <- pExpr
return $ Assign ty name exp
pFunDef = do
name <- pName
lam <- pLam
return $ Assign Nothing name lam
pExpr = pArray <|> try pTable <|> pBlock <|> try pIf <|> try pLam <|> try pLet <|> makeExprParser pTerm operatorTable
pTable = between (symbol "{") (symbol "}") (Table <$> listOf pField)
pField = do nm <- pName
kw ":"
e <- pExpr
return (nm, e)
...
Тут код сразу описывает и грамматику, и построение типизированного AST из нее. Каждая строчка тут или успешно что-то парсит, продвигаясь вперед по тексту и порождая значения, или, если во входном тексте что-то другое, что эта строка не ожидает, прерывается и переходит к следующей альтернативе в выражениях с несколькими альтернативами (разделенными <|>), откатываясь назад в тексте, когда необходимо. Вся эта логика передачи управления туда-сюда и перемещения по входному тексту упрятана в монаду и do-нотацию, за счет чего код не перегружен механикой телодвижений, остается лишь существенная для задачи логика.