, имя будет отражать результат, к которому уже применена функция
>reverse
.
Действие ввода-вывода >fmap (++"!") getLine
ведёт себя в точности как функция >getLine
, за исключением того, что к её результату всегда добавляется строка >"!"
в конец!
Если бы функция >fmap
работала только с типом >IO
, она имела бы тип >fmap :: (a –> b) –> IO a –> IO b.
Функция >fmap
принимает функцию и действие ввода-вывода и возвращает новое действие ввода-вывода, похожее на старое, за исключением того, что к результату, содержащемуся в нём, применяется функция.
Предположим, вы связываете результат действия ввода-вывода с именем лишь для того, чтобы применить к нему функцию, а затем даёте очередному результату какое-то другое имя, – в таком случае подумайте над использованием функции >fmap
. Если вы хотите применить несколько функций к некоторым данным внутри функтора, то можете объявить свою функцию на верхнем уровне, создать анонимную функцию или, в идеале, использовать композицию функций:
>import Data.Char
>import Data.List
>main = do
> line <– fmap (intersperse '-' . reverse . map toUpper) getLine
> putStrLn line
Вот что произойдёт, если мы сохраним этот код в файле fmapping_io.hs, скомпилируем, запустим и введём >"Эй, привет"
:
>$ ./fmapping_io
>Эй, привет
>Т-Е-В-И-Р-П- -,-Й-Э
Выражение >intersperse '-' . reverse . map toUpper
берёт строку, отображает её с помощью функции >toUpper
, применяет функцию >reverse
к этому результату, а затем применяет к нему выражение >intersperse '-'
. Это более красивый способ записи следующего кода:
>(\xs –> intersperse '-' (reverse (map toUpper xs)))
Функции в качестве функторов
Другим экземпляром класса >Functor
, с которым мы всё время имели дело, является >(–>) r
. Стойте!.. Что, чёрт возьми, означает >(–>) r
? Тип функции >r –> a
может быть переписан в виде >(–>) r a
, так же как мы можем записать >2 + 3
в виде >(+) 2 3
. Когда мы воспринимаем его как >(–>) r a
, то >(–>)
представляется немного в другом свете. Это просто конструктор типа, который принимает два параметра типа, как это делает конструктор >Either
.
Но вспомните, что конструктор типа должен принимать в точности один параметр типа, чтобы его можно было сделать экземпляром класса >Functor
. Вот почему нельзя сделать конструктор >(–>)
экземпляром класса >Functor
; однако, если частично применить его до >(–>) r
, это не составит никаких проблем. Если бы синтаксис позволял частично применять конструкторы типов с помощью сечений – подобно тому как можно частично применить оператор >+,
выполнив >(2+)
, что равнозначно >(+)
>2
, – вы могли бы записать >(–>)