52700.fb2
такие же как и для ST (а следовательно и для State). Но при этом, поскольку мы конкретизировали первый
параметр типа ST, мы уже не сможем воспользоваться функцией runST.
Тип RealWorld определён в модуле Control.Monad.ST, там же можно найти и функцию:
stToIO :: ST RealWorld a -> IO a
Интересно, что класс Monad был придуман как раз для решения проблемы ввода-вывода. Классы типов
изначально задумывались для решения проблемы определения арифметических операций на разных числах
и функции сравнения на равенство для разных типов, мало кто тогда догадывался, что классы типов сыграют
такую роль, станут основополагающей особенностью языка.
a
f
IO b
b
g
IO c
До
После
a
g
f
IO c
a
f>>g
IO c
Рис. 8.1: Композиция для монады IO
Посмотрим на (рис. 8.1). Это рисунок для класса Kleisli. Здесь под >> понимается композиция, как мы
её определяли в главе 6, а не метод класса Monad, вспомним определение:
class Kleisli m where
idK
:: a -> m a
(>> ) :: (a -> m b) -> (b -> m c) -> (a -> m c)
Монада IO | 127
Композиция специальных функций типа a -> IO b вносит порядок вычисления. Считается, что сначала
будет вычислена функция слева от композиции, а затем функция справа от композиции. Это происходит за
счёт скрытой передачи фиктивного состояния. Теперь перейдём к классу Monad. Там композиция заменяется
на применение или операция связывания:
ma >>= mf
Для типа IO эта запись говорит о том, что сначала будет выполнено выражение ma и результат будет под-
ставлен в выражение mf и только затем будет выполнено mf. Оператор связывания для специальных функций
вида:
a -> IO b
раскалывает наш статический мир на “до” и “после”. Однажды попав в сети IO, мы не можем из них
выбраться, поскольку теперь у нас нет функции runST. Но это не так страшно. Тип IO дробит наш статический
мир на кадры. Но мы спокойно можем создавать статические чистые функции и поднимать их в мир IO лишь
там где это действительно нужно.
Рассмотрим такой пример, программа читает с клавиатуры начальное значение, затем загружает файл
настроек. Потом запускается, какая-то сложная функция и в самом конце мы выводим результат на экран.
Схематично мы можем записать эту программу так:
program = liftA2 algorithm readInit (readConfig ”file”) >>= print
-- функции с побочными эффектами