2015-10-28 4 views
12

Снова и снова я читал термин эффектно, но я все еще не могу дать четкое определение того, что это значит. Я предполагаю, что правильный контекст effectful вычисления, но я также видел термин effectful values)Что именно означает «эффективный»

Я привык думать, что effectful средства , имеющие побочные эффекты. Но в Haskell нет побочных эффектов (кроме как в некоторой степени IO). Все еще есть эффективные вычисления повсюду.

Затем я прочитал, что монады используются для создания эффективных вычислений. Я могу несколько понять это в контексте Монады State. Но я не вижу никакого побочного эффекта в монаде Maybe. В общем, мне кажется, что Monads, которые обертывают функционально подобную вещь, легче увидеть как производящие побочные эффекты, чем Monads, которые просто обертывают ценность.

Когда речь заходит о Applicative функторах Я еще больше потерян. Я всегда видел аппликативные функторы как способ для map функции с несколькими аргументами. Здесь я не вижу побочного эффекта. Или есть разница между эффектным и с эффектами?

+0

Возможно, полезно: https://slpopejoy.github.io/posts/Effectful01.html Он определяет * effectful * как: 1. Фактические побочные эффекты (IO) 2. Материал, который кажется побочным эффектом (State, Writer и т. д.) 3. Контексты, которые сохраняются над вызовами функций (Reader, State и т. д.). 4. Нелокальный поток управления (возможно, любой из них). –

+3

Большинство монад определены в терминах чистого вычисления, но с точки зрения программиста принято думать, что 'State sa' является императивной процедурой, которая может читать/записывать состояние' s' с побочными эффектами и, наконец, произведите 'a'. Даже если это чисто, иногда бывает удобно притворяться, что это не так. По теме я бы сказал, что эффектные и с эффектами означают одно и то же, даже если они иногда применяются в широком смысле к значениям, обернутым в любую монаду/аппликативную, даже если они не моделируют побочные эффекты. – chi

ответ

3

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

Рассмотрим следующий блок кода:

let 
    y = foo x 
    z = bar y 
in foobar z 

Это вызывает foo, а затем вызывает bar, а затем вызывает foobar, три обычные функции. Достаточно просто, не так ли? Теперь рассмотрим это:

do 
    y <- foo x 
    z <- bar y 
    foobar z 

Это также вызывает три функции, но и незримо называет (>>=) между каждой парой линий, а также. А это означает, что какие-то странные вещи происходят, в зависимости от того, какого типа монады функция работает в.

  • Если это тождество монада, ничего особенного не происходит. Монадическая версия делает то же самое, что и чистая версия. Никаких побочных эффектов нет.

  • Если каждая функция возвращает Maybe -что-то, а затем, если (скажем) bar возвращает Nothing, весь блок кода прерывается. Нормальная функция не может этого сделать. (I.e., в чистом варианте, есть никак не, чтобы не вызывать foobar.) Таким образом, эта версия делает то, что чистая версия не может. Каждая функция может вернуть значение или прервать блок. Это побочный эффект.

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

  • Если каждая функция работает в государственной монаде, то (например) foo может послать некоторые данные непосредственно foobar, в дополнении к стоимости вы можете увидеть пропускание через bar. Опять же, вы не можете делать это с чистыми функциями, так что это побочный эффект.

  • В IO монада, у вас есть всевозможные интересные эффекты. Вы можете сохранять файлы на диск (файл в основном представляет собой гигантскую глобальную переменную), вы даже можете повлиять на работу кода на других компьютерах (мы называем этот сетевой ввод-вывод).

  • Монастырь ST является сокращенной версией монады IO. Он допускает изменчивое состояние, но автономные вычисления не могут влиять друг на друга.

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

  • Продолжение монады позволяет сломать умы людей! Можно утверждать, что можно с чистыми функциями ...

+1

Я согласен с «эффектом», который вы приписываете продолжению монады. Другое, что я не с тобой. Тот факт, что «делать» обозначение скрывает вызов >> =, не делает его эффективным, потому что без этого синтаксического сахара искупление будет столь же эффектным, но не скрывающим >> =.Тот факт, что он выполняет разные вещи в зависимости от типа монады, должен быть монадой, являющейся классом стилей. Такие вещи происходят со всеми типами моделей, эффективными или нет. –

+0

ОК, поэтому очевидно, что 'IO',' ST' и 'STM' возможны только при использовании низкоуровневых материалов, которые обычный код Haskell не может сделать. Строго говоря, все остальные монады - это просто чистый код, который невидимо запускается. Но все же полезно * думать о них как о эффективном вычислении. В какой-то степени это просто вопрос перспективы. – MathematicalOrchid

+0

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

10

side effect является наблюдаемым взаимодействием с окружающей средой (помимо вычисления его результат значения). В Haskell мы стараемся избегать функций с такими побочными эффектами. Это даже относится к действиям IO: когда выполняется действие IO, никаких побочных эффектов не выполняется, они выполняются только тогда, когда действия, предписанные в значении IO, выполняются в пределах main.

Однако при работе с абстракциями, связанными с составлением вычислений, такими как аппликативные функторы и монады, удобно различать фактическое значение и «отдых», которые мы часто называем «эффектом». В частности, если у нас есть тип f от kind* -> *, то в f a часть a является «значением», и все, что остается «остается», является «эффектом».

Я намеренно процитировал термины, поскольку нет точного определения (насколько я знаю), это просто разговорное определение. В некоторых случаях вообще нет значений или нескольких значений. Например, для Maybe «эффект» заключается в том, что не может быть значения (и вычисление прерывается), для «[]» «эффект» заключается в том, что существует несколько (или нулевых) значений. Для более сложных типов это различие может быть еще сложнее.

Различие между «эффектами» и «значениями» на самом деле не зависит от абстракции. Functor, Applicative и Monad просто дайте нам инструменты, что мы с ними можем сделать (Functor s позволяют изменять значения внутри, Applicative s позволяют комбинировать эффекты и Monad s позволяют влиять на эффекты, связанные с предыдущими значениями). Но в контексте Monad с, это несколько проще создать мысленную картину того, что происходит, потому что монадическое действие может «видеть» значение результата предыдущего вычисления, как засвидетельствовано оператор в

(>>=) :: m a -> (a -> m b) -> m b 

: Вторая функция получает значение типа a, поэтому мы можем представить себе, что «предыдущее вычисление имело некоторый эффект, и теперь есть его значение результата, с которым мы можем что-то сделать».

+1

Не могли бы вы подробнее рассказать о «влиянии» на применение? В конце концов, есть статья «Аппликационное программирование с эффектами», и я никогда не понимал названия (я считаю, что понимаю аппликации) –

+2

@MartinDrautzburg Как я уже писал, различие между «эффектами» и «значениями» определяется фактическими данными типа, а не абстракцией, которую мы используем для ее манипулирования. Например, для 'Maybe'« эффект »всегда является то, что вычисление может быть прервано, независимо от того, используется ли интерфейс Applicative или Monad (или другой). Если вы напишете 'f <$> a <*> b <*> c' in 'Maybe', любой из' a', 'b' или' c' может прервать вычисление с помощью 'Nothing', и это его« эффект ». Аппликативный интерфейс позволяет комбинировать эффекты (для 'Maybe' это означает прервать первый« Ничто »), но не позволяет влиять на предыдущие значения. –

1

В обоснование Petr Pudlák's answer здесь приведено аргумент о происхождении более широкого понятия «эффект».

Фраза «effectful программирования» показывает в автореферате McBride и Паттерсон Applicative Programming with Effects, бумага, которая представила аппликативные функторы:

В этой статье мы вводим Applicative функторов - абстрактную характеристику аппликативного стиля Эффективного программирования, слабее, чем Monad и, следовательно, более широко распространены.

«Эффект» и «Эффективный» появляются в нескольких других отрывках из бумаги; эти последствия считаются совершенно незаметными, чтобы не требовать явного разъяснения. Например, это замечание сделано только после определения Applicative представлена ​​(стр. 3):

В каждом примере, есть конструктор типа f, который встраивает обычное понятие стоимости, но поддерживает свой собственный своеобразный способ дать смысл обычного аппликативному языку [...] Мы, соответственно, ввести Applicative класс:

[A Haskell определение из Applicative]

Этого класса обобщающего S и K [т. the S and K combinators, которые отображаются в примере Reader/function Applicative экземпляра] из потоковой обработки среды для нарезки эффекта в целом.

Из этих цитат, мы можем сделать вывод, что в этом контексте:

  • эффекты являются вещи, которые Applicative нити «в целом».

  • Эффекты связаны с конструкторами типов, которые даются Applicative экземплярами.

  • Monad также касается эффектов.

После этих выводов, мы можем проследить это использование «эффекта» по крайней мере к Wadler's papers on monads. Например, вот цитата из стр.6 монад для функционального программирования:

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

И из тех же бумаг, страница 21:

Если монады инкапсулировать эффекты и списки формируют монаду, списки соответствуют некоторому эффекту? Действительно, они делают, и эффект, которым они соответствуют, - это выбор. Можно подумать о вычислении типа [a] как предлагающего выбор значений, по одному для каждого элемента списка. Монадический эквивалент функции типа a → b является функцией типа a → [b].

«соответствует некоторому эффекту» поворот фразы здесь является ключевым: она связывает назад к более простой претензии реферата:

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

Пек является то, что монады могут быть использованы для выражения то, что в «других языках», как правило, закодированных в виде побочных эффектов - то есть, как Петр Pudlák ставит его в ответ здесь, «наблюдаемый взаимодействие с [функциональной] средой (кроме вычисления ее значения результата) ». Благодаря метонимии это легко привело к тому, что «эффект» приобрел второе значение, более широкое, чем «побочный эффект», а именно то, что вводится через конструктор типов, который является экземпляром Monad. Со временем этот смысл был далее обобщен, чтобы охватить другие классы функторов, такие как Applicative, как видно из работы Макбрайда и Паттерсона.

В целом, я считаю, «эффект», чтобы иметь два разумных значений в Haskell просторечии:

  • А «буквальный» или «абсолютный» один: эффект является побочным эффектом; и

  • «Обобщенный» или «относительный»: эффект является функториальным контекстом.

В некоторых случаях можно избежать разногласия по терминологии происходит, когда каждая из участвующих сторон неявно предполагает различное значение «эффекта». Другой возможный спор заключается в том, является ли законным говорить об эффектах при работе с Functor в одиночку, в отличие от подклассов, таких как Applicative или Monad (я считаю, что это нормально, по согласованию с Petr Pudlák's answer to Why can applicative functors have side effects, but functors can't?).

Смежные вопросы