Разделение «чистого» и «нечистого»
В этой главе вы узнаете, как вводить данные с клавиатуры и печатать их на экран. Начнём мы с основ ввода-вывода:
• Что такое действия?
• Как действия позволяют выполнять ввод-вывод?
• Когда фактически исполняются действия?
Вводу-выводу приходится иметь дело с некоторыми ограничениями функций языка Haskell, поэтому первым делом мы обсудим, что с этим можно сделать.
Мы уже упоминали, что Haskell – чисто функциональный язык. В то время как в императивных языках вы указываете компьютеру серию шагов для достижения некой цели, в функциональном программировании мы описываем, чем является то или иное понятие. В языке Haskell функция не может изменить некоторое состояние, например поменять значение переменной (если функция изменяет состояние, мы говорим, что она имеет побочные эффекты). Единственное, что могут сделать функции в языке Haskell, – это вернуть нам некоторый результат, основываясь на переданных им параметрах. Если вызвать функцию дважды с одинаковыми параметрами, она всегда вернёт одинаковый результат. Если вы знакомы с императивными языками, может показаться, что это ограничивает свободу наших действий, но мы видели, что на самом деле это даёт весьма мощные возможности. В императивном языке у вас нет гарантии, что простая функция, которая всего-то навсего должна обсчитать пару чисел, не сожжёт ваш дом, не похитит собаку и не поцарапает машину во время вычислений! Например, когда мы создавали бинарное поисковое дерево, то вставляли элемент в дерево не путём модификации дерева в точке вставки. Наша функция добавления нового элемента в дерево возвращала новое дерево, так как не могла изменить старое.
Конечно, это хорошо, что функции не могут изменять состояние: это помогает нам строить умозаключения о наших программах. Но есть одна проблема. Если функция не может ничего изменить, как она сообщит нам о результатах вычислений? Для того чтобы вывести результат, она должна изменить состояние устройства вывода – обычно это экран, который излучает фотоны; они путешествуют к нашему мозгу и изменяют состояние нашего сознания… вот так-то, чувак!
Но не надо отчаиваться, не всё ещё потеряно. Оказывается, в языке Haskell есть весьма умная система для работы с функциями с побочными эффектами, которая чётко разделяет чисто функциональную и «грязную» части нашей программы. «Грязная» часть выполняет всю грязную работу, например отвечает за взаимодействие с клавиатурой и экраном. Разделив «чистую» и «грязную»части, мы можем так же свободно рассуждать о чисто функциональной части нашей программы, получать все преимущества функциональной чистоты, а именно – ленивость, гибкость, модульность, и при этом эффективно взаимодействовать с внешним миром.