2017-01-24 25 views
3

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

Я понимаю, что для выполнения операции ввода-вывода вы должны использовать «IO-монаду», которая завербовала значение в виде «черного ящика», поэтому любая функция, использующая монаду IO, по-прежнему является чисто функциональной. Хорошо, хорошо, но тогда, где действительно выполняется операция ввода-вывода?

Означает ли это, что сама Монада не является чисто функциональной? Или реализована ли операция ввода-вывода, скажем, в C и «встроена» внутри компилятора Haskell?

Могу ли я писать в чистом Haskell с Монадой или без нее, что-то, что сделает операцию ввода-вывода? А если нет, то откуда эта способность возникает, если это невозможно в самом языке? Если он встроен/связан внутри компилятора Haskell с кусками кода C, будет ли он в конечном итоге вызван IO Monad для выполнения «грязной работы»?

+1

(комментируя, потому что я не уверен на 100%). Я понимаю, что IO моделируется как монашеская государственная монада с «реальным миром» как государство. Компилятор/среда выполнения фактически преобразует это в операции ввода-вывода, которые реализованы с использованием привязок к API операционной системы. Чисто функциональное программирование могло бы вычислить что угодно, но никому об этом не рассказывать. Нам нужно время выполнения, которое может конвертировать эти действия с состоянием в реальном мире в реальные вызовы базовой операционной системе. – bheklilr

+0

https://wiki.haskell.org/IO_inside#Welcome_to_the_RealWorld.2C_baby –

ответ

17

В качестве предисловия это не «IOMonad», несмотря на то, что говорят многие плохо написанные введения. Это просто «тип IO». В монадах нет ничего волшебного. Класс Haskell - довольно скучная вещь - это просто незнакомый и более абстрактный, чем то, что может поддерживать большинство языков. Вы никогда не увидите, чтобы кто-нибудь звонил IO «IOAlternative», хотя IO реализует Alternative. Сфокусировать слишком много на Monad только на пути обучения.

Концептуальная магия для принципиальной обработки эффектов (не побочных эффектов!) В чистых языках - это наличие типа IO. Это настоящий тип. Это не какой-то флаг, говорящий: «Это нечисто!». Это полный тип типа Haskell * -> *, как и Maybe или []. Подписи типов, принимающие значения ввода-вывода в качестве аргументов, например IO a -> IO (Maybe a), имеют смысл. Тип подписи с вложенным IO имеет смысл, например IO (IO a).

Так что, если это настоящий тип, он должен иметь конкретное значение. Maybe a как тип представляет собой возможно отсутствующее значение типа a. [a] означает 0 или больше значений типа a. IO a означает последовательность эффектов, которые производят значение типа a.

Обратите внимание, что цель IO состоит в том, чтобы представить последовательность эффектов. Как я сказал выше, это не побочные эффекты. Они не могут быть скрыты в безобидном виде листа программы и загадочно меняют вещи за спиной другого кода. Вместо этого эффекты довольно явно вызваны тем фактом, что они являются значением IO. Вот почему люди пытаются свести к минимуму часть своей программы, используя типы IO. Чем меньше вы там делаете, тем меньше возможностей для пугающего действия на расстоянии, мешающем вашей программе.

Что касается основной цели вашего вопроса, то - полная программа Haskell - это значение IO, называемое main, и набор определений, которые он использует. Компилятор, когда он генерирует код, вставляет явно не-Haskell блок кода, который фактически выполняет последовательность эффектов в значении IO. В некотором смысле это то, о чем Симон Пейтон Джонс (один из давних авторов GHC) заходил в своем разговоре Haskell is useless.

Это правда, что все, что на самом деле выполняет IO-действие, не может оставаться концептуально чистым.(И есть эта очень нечистая функция, которая запускает действия IO, выставленные на языке Haskell. Я не буду говорить об этом больше, чем она была добавлена ​​для поддержки интерфейса внешних функций, и использование этого неправильно будет очень сильно нарушать вашу программу.) Но точка Haskell заключается в том, чтобы обеспечить принципиальный интерфейс для системы эффектов и скрыть беспринципные биты. И он делает это таким образом, который на самом деле очень полезен на практике.