STDOUT та його домішка


10

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

Однією з головних ідей функціонального програмування є те, що той самий вхід завжди повинен давати однаковий вихід. Тому, скажімо, запит до бази даних чи файлу запису за визначенням не можна було виконати у чистому функціональному стилі. Наприклад, це одна з причин, коли нам потрібні монади.

Питання - чому ми розглядаємо STDOUT вихід як щось нечисте? Так, будь-який файл-обробник ризикований - ми ніколи не можемо бути впевнені, що дані завжди будуть записуватися. А як щодо STDOUT? Чому ми повинні думати про це як про щось ненадійне? Чи більш надійною є сама оцінка? Я маю на увазі, ми завжди можемо натиснути на курок і, таким чином, перервати обчислення.

Відповіді:


6

Тому, скажімо, запит до бази даних чи файлу запису за визначенням не можна було виконати у чистому функціональному стилі. Наприклад, це одна з причин, коли нам потрібні монади.

Нікому не потрібні монади, це лише один із способів описати речі. Насправді це, мабуть, навіть не найкращий спосіб. Деяка форма типізації ефектів , унікальність типів або система, що базується на повній лінійній логіці , теоретично виглядають переконливішими, але все це більш радикальні відступи від відомих систем типу і складніші для вираження. Monadic IO, як знайдено в Haskell, є компромісом між зручністю та простотою, оскільки він, по суті, моделює повністю імперативне програмування таким чином, що легко співіснував із існуючою системою типу ML, яка вже використовується в мові.

Питання - чому ми розглядаємо STDOUT вихід як щось нечисте? Так, будь-який файл-обробник ризикований - ми ніколи не можемо бути впевнені, що дані завжди будуть записуватися. А як щодо STDOUT? Чому ми повинні думати про це як про щось ненадійне? Чи більш надійною є сама оцінка? Я маю на увазі, ми завжди можемо натиснути на курок і, таким чином, перервати обчислення.

Це не так, і ми ні. Введення та вихід із програми в цілому можна просто розглядати як аргументи та результати трактування всієї програми як однієї великої чистої функції. Поки він друкує одне і те ж, що і для stdout, якщо ви живите ним одне і те ж з stdin, це все ще є чистою функцією. Насправді, перед тим, як запровадити монадійний IO, Haskell використовував потокову систему вводу / виводу, яка використовувала чисті ледачі потоки для введення та виведення. Це впало, тому що це було, мабуть, біль, яка може дати вам уявлення про те, чому ви не чули нічого подібного. :]

Щоб зробити сенс дурнішим, розгляньте мінімалістичну езотеричну мову, Lazy K :

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

Що відрізняє Lazy K від інших таких мов, це майже повна відсутність інших функцій. Наприклад, вона не пропонує інтегровану систему поліморфного типу Hindley-Milner. Він не постачається з великою стандартною бібліотекою з підтримкою незалежного від платформи програмування графічного інтерфейсу та прив’язки до інших мов. Не можна також писати будь-яку подібну бібліотеку, оскільки, між іншим, Lazy K не забезпечує жодного способу визначення або посилання на будь-які функції, крім вбудованих. Ця нездатність доповнюється відповідним відсутністю підтримки чисел, рядків або будь-якого іншого типу даних. Тим не менш, Lazy K - Тюрінг-повний.

(...)

Програми Lazy K живуть у тій же позачасовій платонічній царині, що і математичні функції, яку сторінка Unlambda називає "блаженною цариною чистого нетипового числення лямбда". Так само, як збирання сміття приховує від програміста процес управління пам’яттю, так і референтна прозорість приховує процес оцінювання. Те, що деякий розрахунок необхідний для того, щоб переглянути картину набору Мандельброта, або для того, щоб "запустити" програму Lazy K, є деталізацією реалізації. У цьому суть функціонального програмування.

(...)

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

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


Майте на увазі, що вищезазначене стосується лише по суті прийняття вводу та виводу чистої функції та підключення їх до stdin / stdout «зовні». Існує велика різниця між цим і наявністю доступу до реальних примітивів вводу / виводу на рівні системи. Деталі про реалізацію читання та запису в потоки можуть витікати домішками, якщо ретельно не зафіксовані.

Я вважаю, що це головна причина того, що ви не можете зробити це безпосередньо в Haskell - розумні випадки використання є тонкими порівняно з використанням монадичного IO, і для останнього є багато користі від доступу до реальної речі. Я вважаю, що тому, наприклад, аргументи командного рядка для програми не передаються просто аргументами main, хоча інтуїтивно здається, що вони повинні бути.

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


Сер, мушу зізнатися, мені подобається будь-яка ваша відповідь на будь-якій з груп. Ви обов'язково повинні написати книгу Haskell, і я НЕ жартую.
shabunc

@shabunc: Іноді я замислювався про те, наскільки сумарною є кількість моїх відповідей на те, що вже є розмір книги ...
CA McCann

Чи можете ви навести приклад системи, заснованої на повній лінійній логіці? Це здається цікавим, якщо воно існує.
конфігуратор

@configurator: Зауважте, як я пов’язував певні мови для інших, але сторінку вікіпедії для лінійної логіки? На жаль, якби у мене був приклад, я б його наводив. : [Все, що я чув, - це часткові прототипи та експериментальні системи досліджень CS. Якщо ви хочете заглибитися в це, ось кілька відносно доступних матеріалів про системи лінійного типу, які можуть вас почати.
CA McCann

3

Хоча чистота у функціональній програмі є гідною ціллю, реальність полягає в тому, що кожна нетривіальна корисна програма матиме певну домішку (або "побічні ефекти") з причин, про які ви згадали.

Повністю чисті програми, за визначенням, є запечатаною чорною скринькою і по суті нецікаві.

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


впевнений, ти маєш рацію. Але я розумію, чому 100% чистота - це утопія. Я запитую лише про STDOUT.
shabunc

1
STDOUT - побічний ефект, як і будь-який інший. Всередині монада проводить будь-яку перевірку помилок, яка може знадобитися.
Роберт Харві

так, саме це питання - чому воно вважається побічним ефектом, як і будь-яке інше?
shabunc

2
Все, що модифікує зовнішній світ, вважається побічним ефектом.
Роберт Харві

1

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

Також STDOUT не завжди є "консольним екраном". Іноді це передається в іншу програму. Іноді трубу ламають.


0

Це допомагає, якщо ви думаєте про чистоту в термінах "Змінює стан зовнішнього світу". Це може включати запис на консоль, файл журналу, вилучення компакт-диска або "запуск ракет".

Це також може бути проблемою з точки зору одночасного виконання. Якщо ви знаєте, що функція не має побічних ефектів, ви можете легко домовитися про одночасність, оскільки ви можете довести, що не може бути ніяких перегонових умов тощо.


Змінюється стан зовнішнього світу або залежить від стану зовнішнього світу. Дивіться це запитання для більшого обговорення у цьому напрямку.
MatrixFrog
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.