>"Небольшая банда.")
– и мы хотим передать его функции
>isBigGang
. Похоже, перед нами снова встаёт вопрос: если у нас есть функция, которая принимает нормальное значение и возвращает значение с контекстом, как нам взять нормальное значение с контекстом и передать его функции?
Исследуя монаду >Maybe
, мы создали функцию >applyMaybe
, которая принимала значение типа >Maybe a
и функцию типа >a –> Maybe b
и передавала это значение >Maybe a
в функцию, даже если функция принимает нормальное значение типа >a
вместо >Maybe a
. Она делала это, следя за контекстом, имеющимся у значений типа >Maybe a
, который означает, что эти значения могут быть значениями с неуспехом вычислений. Но внутри функции типа >a –> Maybe b
мы могли обрабатывать это значение как нормальное, потому что >applyMaybe
(которая позже стала функцией >>>=
) проверяла, являлось ли оно значением >Nothing
либо значением >Just
.
В том же духе давайте создадим функцию, которая принимает значение с присоединённым журналом, то есть значением типа >(a,String)
, и функцию типа >a –> (b,String)
, и передаёт это значение в функцию. Мы назовём её >applyLog
. Однако поскольку значение типа >(a,String)
не несёт с собой контекст возможной неудачи, но несёт контекст добавочного значения журнала, функция >applyLog
будет обеспечивать сохранность первоначального значения журнала, объединяя его со значением журнала, возвращаемого функцией. Вот реализация этой функции:
>applyLog :: (a,String) –> (a –> (b,String)) –> (b,String)
>applyLog (x,log) f = let (y,newLog) = f x in (y,log ++ newLog)
Когда у нас есть значение с контекстом и мы хотим передать его функции, то мы обычно пытаемся отделить фактическое значение от контекста, затем пытаемся применить функцию к этому значению, а потом смотрим, сбережён ли контекст. В монаде >Maybe
мы проверяли, было ли значение равно >Just x
, и если было, мы брали это значение >x
и применяли к нему функцию. В данном случае очень просто определить фактическое значение, потому что мы имеем дело с парой, где один компонент является значением, а второй – журналом. Так что сначала мы просто берём значение, то есть >x
, и применяем к нему функцию >f
. Мы получаем пару >(y,newLog)
, где >y
является новым результатом, а >newLog
– новым журналом. Но если мы вернули это в качестве результата, прежнее значение журнала не было бы включено в результат, так что мы возвращаем пару >(y,log ++ newLog)
. Мы используем операцию конкатенации >++
, чтобы добавить новый журнал к прежнему.
Вот функция >applyLog
в действии:
>ghci> (3, "Небольшая банда.") `applyLog` isBigGang