Есть несколько подходов к этому. Одна вещь, которую вам просто нужно принять, это то, что в какой-то момент существует волшебная нечистая машина, которая берет чистые выражения и делает их нечистыми, взаимодействуя с окружающей средой. Вы не должны задавать вопросы об этой волшебной машине.
Есть два подхода, которые я могу придумать навскидку. Существует по крайней мере третья, о которой я забыл.
Потоки ввода/вывода
Подход, который проще всего понять, может заключаться в потоковом вводе-выводе. Ваша функция main
принимает один аргумент: поток событий, произошедших в системе, включая нажатия клавиш, файлы в файловой системе и так далее. Ваша функция main
также возвращает одну вещь: поток событий, которые вы хотите произвести в системе.
Заметьте, потоки похожи на списки, только вы можете создавать их по одному элементу за раз, и получатель получит элемент, как только вы его создадите. Ваша чистая программа читает из такого потока и добавляет к своему собственному потоку, когда она хочет, чтобы система что-то сделала.
Клей, который заставляет всю эту работу работать, — это волшебная машина, которая находится вне вашей программы, читает из потока «запросов» и помещает информацию в поток «ответов». Пока ваша программа чиста, эта волшебная машина — нет.
Выходной поток может выглядеть так:
[print('Hello, world! What is your name?'), input(), create_file('G:\testfile'), create_file('C:\testfile'), write_file(filehandle, 'John')]
и соответствующий входной поток будет
['John', IOException('There is no drive G:, could not create file!'), filehandle]
Видите, как input
в out-stream привело к появлению 'John'
во in-stream? Это принцип.
Монадический ввод-вывод
Монадический ввод-вывод — это то, что делает Haskell, и делает это очень хорошо. Вы можете представить это как построение гигантского дерева команд ввода-вывода с операторами, чтобы склеить их вместе, а затем ваша функция main
возвращает это массивное выражение волшебной машине, которая находится вне вашей программы и выполняет команды и выполняет указанные операции. Эта волшебная машина нечиста, в то время как ваша программа построения выражения чиста.
Возможно, вы захотите представить, что это дерево команд выглядит примерно так:
main
|
+---- Cmd_Print('Hello, world! What is your name?')
+---- Cmd_WriteFile
|
+---- Cmd_Input
|
+---+ return validHandle(IOResult_attempt, IOResult_safe)
+ Cmd_StoreResult Cmd_CreateFile('G:\testfile') IOResult_attempt
+ Cmd_StoreResult Cmd_CreateFile('C:\testfile') IOResult_safe
Первое, что он делает, это печатает приветствие. Следующее, что он делает, это то, что он хочет записать файл. Чтобы иметь возможность писать в файл, ему сначала нужно прочитать из ввода все, что он должен записать в файл. Затем предполагается, что у него есть дескриптор файла для записи. Он получает это от функции с именем validHandle
, которая возвращает действительный дескриптор двух альтернатив. Таким образом, вы можете смешивать то, что выглядит как нечистый код, с тем, что выглядит как чистый код.
Это «объяснение» граничит с вопросами о волшебной машине, о которой вы не должны задавать вопросов, поэтому я собираюсь завершить это несколькими мудрыми советами.
Реальный монадический ввод-вывод не похож на мой пример. Мой пример — одно из возможных объяснений того, как монадический ввод-вывод может выглядеть «под капотом», не нарушая чистоты.
не пытайтесь использовать мои примеры, чтобы понять, как работать с чистым вводом-выводом. То, как что-то работает под капотом, совершенно отличается от того, как вы это делаете. Если бы вы никогда в жизни не видели машину, вы бы не стали хорошим водителем, читая чертежи для нее.
Причина, по которой я продолжаю говорить, что вы не должны задавать вопросы о волшебной машине, которая на самом деле что-то делает, заключается в том, что когда программисты что-то изучают, они, как правило, хотят поковыряться в машине, чтобы попытаться понять ее. Я не рекомендую делать это для чистого ввода-вывода. Механизм может ничему вас не научить тому, как использовать различные варианты ввода-вывода.
Это похоже на то, как вы не изучаете Java, глядя на дизассемблированный байт-код JVM.
Обязательно научиться использовать монадический ввод-вывод и потоковый ввод-вывод. Это классный опыт, и всегда хорошо иметь больше инструментов под своим поясом.
person
kqr
schedule
11.08.2013