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

. Рассматривая эту аналогию с ящиками на ножках, вы можете понять, каким образом тип >IO действует как функтор.

Давайте посмотрим, как же это тип >IO является экземпляром класса >Functor… Когда мы используем функцию >fmap для отображения действия ввода-вывода с помощью функции, мы хотим получить обратно действие ввода-вывода, которое делает то же самое, но к его результирующему значению применяется наша функция. Вот код:

>instance Functor IO where

>   fmap f action = do

>      result <– action

>      return (f result)

Результатом отображения действия ввода-вывода с помощью чего-либо будет действие ввода-вывода, так что мы сразу же используем синтаксис >do для склеивания двух действий и создания одного нового. В реализации для метода >fmap мы создаём новое действие ввода-вывода, которое сначала выполняет первоначальное действие ввода-вывода, давая результату имя >result. Затем мы выполняем >return (f result). Вспомните, что >return – это функция, создающая действие ввода-вывода, которое ничего не делает, а только возвращает что-либо в качестве своего результата.

Действие, которое производит блок >do, будет всегда возвращать результирующее значение своего последнего действия. Вот почему мы используем функцию >return, чтобы создать действие ввода-вывода, которое в действительности ничего не делает, а просто возвращает применение >f result в качестве результата нового действия ввода-вывода. Взгляните на этот кусок кода:

>main = do

>   line <– getLine

>   let line' = reverse line

>   putStrLn $ "Вы сказали " ++ line' ++ " наоборот!"

>   putStrLn $ "Да, вы точно сказали " ++ line' ++ " наоборот!"

У пользователя запрашивается строка, и мы отдаём её обратно пользователю, но в перевёрнутом виде. А вот как можно переписать это с использованием функции >fmap:

>main = do

>   line <– fmap reverse getLine

>   putStrLn $ "Вы сказали " ++ line ++ " наоборот!"

>   putStrLn $ "Да, вы точно сказали " ++ line ++ " наоборот!"

Так же как можно отобразить >Just "уфф" с помощью отображения >fmap reverse, получая >Just "ффу", мы можем отобразить и функцию >getLine с помощью отображения >fmap>reverse. Функция >getLine – это действие ввода-вывода, которое имеет тип >IO>String, и отображение его с помощью функции >reverse даёт нам действие ввода-вывода, которое выйдет в реальный мир и получит строку, а затем применит функцию >reverse к своему результату. Таким же образом, как мы можем применить функцию к тому, что находится внутри коробки >Maybe, можно применить функцию и к тому, что находится внутри коробки >IO, но она должна выйти в реальный мир, чтобы получить что-либо. Затем, когда мы привязываем результат к имени, используя запись