STDOUT и его примеси

10

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

Одна из основных идей функционального программирования заключается в том, что один и тот же вход всегда должен давать один и тот же результат. Поэтому, скажем, запрос к базе данных или запись файла не могут быть выполнены в чисто функциональном стиле по определению. Это, например, одна из причин, по которой нам нужны монады.

Вопрос в том, почему мы рассматриваем вывод STDOUT как нечто нечистое? Да, любой обработчик файлов рискован - мы никогда не можем быть уверены, что данные всегда будут записаны. Но как насчет STDOUT? Почему мы должны думать об этом как о чем-то ненадежном? Является ли более ненадежной сама оценка? Я имею в виду, мы всегда можем нажать триггер и, таким образом, вычислить прерывание.

shabunc
источник

Ответы:

6

Поэтому, скажем, запрос к базе данных или запись файла не могут быть выполнены в чисто функциональном стиле по определению. Это, например, одна из причин, по которой нам нужны монады.

Никому не нужны монады, это всего лишь один способ описать вещи. На самом деле, это, вероятно, даже не самый лучший способ. Некоторая форма типизации эффектов , типы уникальности или система, основанная на полной линейной логике, кажутся более убедительными в теории, но все они более радикально отличаются от хорошо известных систем типов и более сложны для выражения. Монадический ввод-вывод, обнаруженный в Haskell, представляет собой компромисс между удобством использования и простотой, поскольку он по существу моделирует полностью императивное программирование таким образом, который легко сосуществовал с существующей системой типов в стиле ML, уже используемой в языке.

Вопрос в том, почему мы рассматриваем вывод STDOUT как нечто нечистое? Да, любой обработчик файлов рискован - мы никогда не можем быть уверены, что данные всегда будут записаны. Но как насчет STDOUT? Почему мы должны думать об этом как о чем-то ненадежном? Является ли более ненадежной сама оценка? Я имею в виду, мы всегда можем нажать триггер и, таким образом, вычислить прерывание.

Это не так, а мы нет. Ввод и вывод из программы в целом можно просто рассматривать как аргументы и результаты обработки всей программы как одной большой чистой функции. Пока он выводит одно и то же на стандартный вывод, если вы передаете ему то же самое с стандартного ввода, это все еще чистая функция. Фактически, до введения монадического ввода-вывода, Haskell использовал систему ввода-вывода на основе потоков, которая использовала чистые ленивые потоки для ввода и вывода. Он уронил его, потому что, по-видимому, было неудобно использовать, что может дать вам некоторое представление о том, почему вы не слышали ничего подобного. :]

Чтобы сделать это более глупо, рассмотрим минималистский эзотерический язык Lazy K :

Lazy K - это собранный мусором, ссылочно-прозрачный функциональный язык программирования с простой потоковой системой ввода-вывода.

Что отличает Lazy K от других таких языков, так это почти полное отсутствие других функций. Например, он не предлагает интегрированную систему полиморфных типов Хиндли-Милнера. Он не поставляется с обширной стандартной библиотекой с поддержкой независимого от платформы программирования GUI и привязок к другим языкам. Ни одна из таких библиотек не может быть написана, поскольку, среди прочего, Lazy K не предоставляет никакого способа определения или ссылки на какие-либо функции, кроме встроенных. Эта неспособность дополняется отсутствием соответствующей поддержки чисел, строк или любых других типов данных. Тем не менее, Lazy K завершен по Тьюрингу.

(...)

Программы Lazy K живут в том же вечном платоновском царстве, что и математические функции, что на странице Unlambda называется «благословенным царством чистого нетипизированного лямбда-исчисления». Как сборщик мусора скрывает процесс управления памятью от программиста, так и ссылочная прозрачность скрывает процесс оценки. Тот факт, что некоторые вычисления необходимы для просмотра изображения набора Мандельброта или для «запуска» программы Lazy K, является подробностью реализации. В этом суть функционального программирования.

(...)

Как обрабатывать ввод и вывод на языке без побочных эффектов? В определенном смысле ввод и вывод не являются побочными эффектами; они, так сказать, фронтальные и обратные эффекты. Так и в Lazy K, где программа просто рассматривается как функция из пространства возможных входов в пространство возможных выходов.

Я сомневаюсь, что вы найдете более чисто функциональный язык, чем этот!


Имейте в виду, однако, что вышеупомянутое применимо только к тому, чтобы по существу взять ввод и вывод чистой функции и каким-то образом подключить их к stdin / stdout «извне». Существует большая разница между этим и наличием доступа к реальным примитивам ввода-вывода системного уровня. Детали реализации чтения и записи в потоки могут не содержать примесей, если не будут тщательно инкапсулированы.

Я ожидаю, что это главная причина, по которой вы не можете сделать это напрямую в Haskell - разумные варианты использования невелики по сравнению с использованием монадического ввода-вывода, и для последнего есть много преимуществ в доступе к реальному. Я полагаю, что именно поэтому, например, аргументы командной строки для программы не просто передаются в качестве аргументов main, хотя интуитивно кажется, что они должны быть.

Вы можете восстановить минимальную версию чего - то подобное в конкретной программе, хотя - просто захватить аргументы как чистые ценности , а затем использовать в interactфункцию для остальной части вашей программы.

CA Макканн
источник
Сэр, я должен признаться, мне нравится любой ваш ответ на любой из стеков. Вы определенно должны написать книгу на Хаскелле, и я НЕ шучу.
Шабун
@shabunc: Я иногда задавался вопросом, насколько близка общая сумма моих ответов по SO к размеру книги…
CA McCann
Не могли бы вы привести пример системы, основанной на полной линейной логике? Это кажется интересным, если оно существует.
конфигуратор
@configurator: Заметьте, как я связался с определенными языками для других, кроме страницы википедии для линейной логики? Увы, если бы у меня был пример, я бы его дал. : [Все, что я слышал, это частичные прототипы и экспериментальные системы из исследований CS. Если вы хотите углубиться в это, вот несколько относительно доступных материалов по системам линейного типа, которые могут помочь вам начать.
CA Макканн
3

Хотя чистота в функциональной программе является достойной целью, реальность такова, что каждая нетривиальная, полезная программа будет иметь некоторую нечистоту (или «побочные эффекты») по причинам, которые вы упомянули.

Полностью чистые программы, по определению, представляют собой закрытый черный ящик и по сути неинтересны.

Функциональный язык Haskell решает эту проблему, изолируя побочные эффекты, такие как вывод в монады . Монада сохраняет чисто функциональный стиль программирования, в то же время позволяя производить вывод.

Роберт Харви
источник
конечно, ты прав. Но я понимаю, почему 100% чистота - это утопия. Я вопрос только о STDOUT.
Шабун
1
STDOUT - это побочный эффект, как и любой другой. Внутри монада будет выполнять любую проверку ошибок, которая может потребоваться.
Роберт Харви
да, это то, о чем этот вопрос - почему он считается побочным эффектом, как и любой другой?
Шабун
2
Все, что изменяет внешний мир, считается побочным эффектом.
Роберт Харви
1

Запись в STDOUT может завершиться неудачно, если вы не подключены к терминальному устройству или если вы (по какой-то причине) закрыли дескриптор файла для него.

Кроме того, STDOUT не всегда является «экраном консоли». Иногда это передается в другую программу. Иногда труба сломана.

Ям Маркович
источник
0

Это помогает, если вы думаете о чистоте в терминах «Изменяет состояние внешнего мира». Это может включать запись в консоль, файл журнала, извлечение компакт-диска или «Запуск ракет».

Это также может быть проблемой с точки зрения одновременного выполнения. Если вы знаете, что функция не имеет побочных эффектов, вы можете легко организовать параллелизм, поскольку вы можете доказать, что не может быть никаких условий гонки или чего-либо подобного.

Захари К
источник
Изменяет состояние внешнего мира или зависит от состояния внешнего мира. Смотрите этот вопрос для дальнейшего обсуждения в этом направлении.
MatrixFrog