52700.fb2 Учебник по Haskell - читать онлайн бесплатно полную версию книги . Страница 279

Учебник по Haskell - читать онлайн бесплатно полную версию книги . Страница 279

Prelude> [ [x,y] | x <- ”Hello”, y <- ”World”]

[”HW”,”Ho”,”Hr”,”Hl”,”Hd”,”eW”,”eo”,”er”,”el”,

”ed”,”lW”,”lo”,”lr”,”ll”,”ld”,”lW”,”lo”,”lr”,

”ll”,”ld”,”oW”,”oo”,”or”,”ol”,”od”]

Сахар для монад, do-нотация

Монады используются столь часто, что для них придумали специальный синтаксис, который облегчает

подстановку специальных значений в функции нескольких переменных. Монады позволяют комбинировать

специальные функции вида

a -> m b

Если бы эти функции выглядели как обычные функции:

a -> b

их можно было свободно комбинировать с другими функциями. А так нам постоянно приходится поль-

зоваться методами класса Monad. Очень часто функции с побочными эффектами имеют вид:

a1 -> a2 -> a3 -> ... -> an -> m b

А теперь представьте, что вам нужно подставить специальное значение третьим аргументом такой функ-

ции и затем передать ещё в одну такую же функцию. Для облегчения участи программистов было придумано

специальное окружение do, в котором специальные функции комбинируются так словно они являются обыч-

ными. Для этого используется обратная стрелка. Посмотрим как определяется функция sequence в окруже-

нии do:

sequence :: [m a] -> m [a]

sequence []

= return []

sequence (mx:mxs)

= do

x

<- mx

xs <- sequence mxs

return (x:xs)

Во втором уравнении сначала мы говорим вычислителю словом do о том, что выражения записаны в мире

монады m. Запись с перевёрнутой стрелкой x <- mx означает, что мы далее в do-блоке можем пользоваться

значением x так словно оно имеет тип просто a, но не m a. Смотрите в этом определении мы сначала извле-

каем первый элемент списка, затем извлекаем хвост списка, приведённый к типу m [a], и в самом конце мы

соединяем голову и хвост и в самом конце оборачиваем результат в специальное значение.

Например мы можем построить функцию, которая дважды читает строку со стандартного ввода и затем

возвращает объединение двух строк:

252 | Глава 17: Дополнительные возможности

getLine2 :: IO String

getLine2 = do

a <- getLine

b <- getLine

return (a ++ b)

В do-нотации можно вводить локальные переменные с помощью слова let:

t = do

b <- f a

c <- g b

let x = c + b

y = x + c

return y

Посмотрим как do-нотация переводится в выражение, составленное с помощью методов класса Monad:

do