Использование нотации do с типом Writer
Теперь, когда у нас есть экземпляр класса Monad, мы свободно можем использовать нотацию do для значений типа Writer. Это удобно, когда у нас есть несколько значений типа Writer и мы хотим с ними что-либо делать. Как и в случае с другими монадами, можно обрабатывать их как нормальные значения, и контекст сохраняется для нас. В этом случае все моноидные значения, которые идут в присоединённом виде, объединяются с помощью функции mappend, а потому отражаются в окончательном результате. Вот простой пример использования нотации do с типом Writer для умножения двух чисел:
import Control.Monad.Writer
logNumber :: Int –> Writer [String] Int
logNumber x = Writer (x, ["Получено число: " ++ show x])
multWithLog :: Writer [String] Int
multWithLog = do
a <– logNumber 3
b <– logNumber 5
return (a*b)
Функция logNumber принимает число и создаёт из него значение типа Writer. Для моноида мы используем список строк и снабжаем число одноэлементным списком, который просто говорит, что мы получили это число. Функция multWithLog – это значение типа Writer, которое перемножает 3 и 5 и гарантирует включение прикреплённых к ним журналов в окончательный журнал. Мы используем функцию return, чтобы вернуть значение (a*b) в качестве результата. Поскольку функция return просто берёт что-то и помещает в минимальный контекст, мы можем быть уверены, что она ничего не добавит в журнал. Вот что мы увидим, если выполним этот код:
ghci> runWriter multWithLog
(15,["Получено число: 3","Получено число: 5"])