Изучай Haskell во имя добра! (Липовача) - страница 244

>"Небольшая банда.") – и мы хотим передать его функции >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