2014-09-14 3 views
5

В чем смысл концепции Эффект в Эффективное прикладное программирование?Что такое аппликативные эффекты?

Например, какие части выражений приведены ниже: ?

[(+1)] <*> [2,3] 
Just (+1) <*> Nothing 
+2

Я сомневаюсь, что эти термины используются в стандарте Haskell. Возможно, было бы полезно услышать/прочитать их в том контексте, который у вас есть. – Shoe

+0

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

ответ

3

Много путаницы было вызвано неудачным выбором имен, как это довольно часто встречается в Haskell (думаю, «return», гораздо лучше названо «emit»).

pure x не является чистым, это x, что чисто, pure просто инъекционные. Это был envisioned to be used in pure f <*> a <*> b <*> ... узор, позволяющий нам эффективно применять чистую функцию f.

Вы можете представить себе обозначив Аппликативный, который посылает глашатай к городским воротам, чтобы объявить каждое значение, которое он получает pure), и чьими применять (<*>) объявляет каждый результат она производит; то pure x просто означает x, о котором кричали о городских воротах. Эффект - это плач, поэтому pure x будет эффектно значение x. И мы могут написать (около) это, как просто pure x, на нашем чистом языке.

[] аппликативны позволяют нам «недетерминировано» применяется (<*>, не $) в недетерминированное значении (не два значения, в вашем примере) для недетерминистических функций; Недетерминизм - эффект.

В приведенном списке [(+1), (+2)] является недетерминированной функцией, которая может увеличивать значение на 1, а также может увеличивать ее на 2. [3,4,5] - это неопределенное значение, возможные значения которого перечислены. Так же, как мы применяем обычные объекты (+1) и 3, как правило, (+1) $ 3, поэтому мы можем применять не детерминированные значения недетерминистически, как [(+1)] <*> [3]10 или [(+1),(+2)] <*> [3,4,5].

И с Maybeвозможность отказа - эффект.

+0

Мне нравится ваше объяснение, где «чисто» получил свое имя. –

+0

@MichaelSteele, о чем говорится в статье: «Мы собираем значения некоторых эффективных вычислений, которые затем будем использовать в качестве аргументов чистой функции' (:) '* *. –

5

В мире FP, эффект любого типа конструктора, таких как Maybe, [], IO и т.д. эффекты не следует путать с побочными эффектами. Интуитивно, эффект является дополнительным свойством ценности, которую вы вычисляете. Maybe Int означает, что ваша программа вычисляет Int с эффектом сбоя, или [Int] означает, что ваша программа вычисляет Int, но с недетерминированным эффектом (здесь определяется недетерминированный результат как список возможных результатов).

Отправляясь отсюда, у нас есть условия аппликативных эффектов и монадических эффекты, которые означают, что указанные эффекты имеют Applicative и Monad экземпляров.

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

+0

'[]' сам по себе не является эффектом, '([], pure :: a -> [a], (<*>) :: [a-> b] -> [a] -> [b])' является эффектом, учитывая некоторые реализации 'pure' и' (<*>) '. –

+0

@WillNess Почему вы называете это просто эффектом, а не эффектом _applicative_? По моему опыту, любой тип конструктора вида '* -> *' называется эффектом без упоминания «Аппликативный» или «Монад». –

+0

«Применимость» подразумевается здесь. :) Я имел в виду «эффект», как в контексте этого вопроса о применении. Без 'pure' и' <*> '(или' return' и '>> =') в виду, что * является * эффектом '[]'? –

5

Можно сказать, что эффект типа f a - это все, что не может быть записано как pure x, где x :: a.

В приложении [], pure x = [x], поэтому [(+1)] = pure (+1), вероятно, не следует рассматривать как эффект. Аналогично в приложении Maybe, pure = Just, поэтому Just (+1) не влияет.

Это оставляет [2,3] и Nothing как эффекты в ваших соответствующих примерах. Это делает интуитивный смысл с точки зрения, что [] обозначает недетерминированные вычисления: [2,3] недетерминированно выбирает между 2 и 3; и перспектива, что Maybe обозначает неудачные вычисления: Nothing не выполняет вычисления.

Определение, которое я использовал, чтобы эффект (возможно, «побочный эффект» был бы лучшим словом) - это то, что невозможно написать, поскольку pure x - это просто качание, чтобы ваш вопрос был точным и не представлял никакого рода консенсуса или стандартного определения. Will Ness's answer дает другую перспективу, что pure генерирует эффективные вычисления из чистого значения, которое имеет хорошее математическое кольцо для него - то есть это определение, вероятно, будет проще использовать при точном настройке.

+0

'pure x' не является чистым, это' x', что является чистым. 'pure x' всегда является эффективным« х », по определению. 'pure (+1) :: [(Num a) => a-> a]' - эффективная функция приращения - a * недетерминированная * функция приращения. Подразумеваемый недетерминизм * есть * эффект. –

+0

Я попытался объяснить больше, что я имел в виду, в моем ответе. Конечно, все зависит от нашего POV: мы можем видеть вещи в терминах 'concatMap', а сам Haskell полностью детерминирован, конечно, но иногда мы предпочитаем думать в терминах недетерминированного применения. Важно также не смешивать эффекты и побочные эффекты, как указывает [еще один ответ ниже] (http://stackoverflow.com/a/25838314/849891). –

4

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

Рассмотрим это выражение:

x + y :: Int 

Это выражение не является effectful; он имеет дело только с регулярными, равными значениями, так сказать. Но мы можем также иметь эффектно дополнение.

Один из способов отказ; вычисление может потерпеть неудачу или преуспеть. Если это не удается, то вычисление прекращается. Это просто тип Maybe.

Just (+1) <*> Nothing :: Maybe Int 

Кроме обычных значений, вы просто добавляете числа вместе. Но теперь у нас есть дополнение, которое может сбой. Поэтому мы должны добавить числа вместе при условии, что вычисление не сработало. В этом выражении мы видим, что вычисление не будет выполнено, поскольку второй операнд равен Nothing.

Если ваши вычисления могут завершиться с ошибкой не только по одной причине, возможно, вы захотите иметь сообщения об ошибках, сообщающие о произошедшем сбое. Тогда вы можете использовать error эффект, который может быть представлен как что-то вроде Either String (String - тип сообщения об ошибке). Реализация этого Applicative ведет себя аналогично MaybeApplicative.

Другим примером эффекта является синтаксический анализ. Анализ может быть реализован путем использования конструкторов и обеспечения их эффективности. Предположим, вы хотите реализовать простой арифметический язык с добавлением и умножением. Это может быть ваше абстрактное синтаксическое дерево (AST):

data Exp = Num Int | Var String 
data AST = Add Exp Exp | Multiply Exp Exp 

Вы создаете AST, просто используя эти конструкторы. Но проблема в том, что вам также нужно фактически анализировать текст, так что как насчет акта разбора? Как насчет отслеживания того, сколько текста вы потратили? Что делать, если синтаксический анализ не удался, потому что текст не соответствовал вашей грамматике? Ну, в библиотеках вроде Parsec, то есть синтаксический анализ эффект. Вы используете некоторый тип данных Parse (то есть экземпляр Applicative) и поднимите конструкторы в эффективный мир Parse AST. Теперь вы можете построить AST, фактически анализируя текст, потому что синтаксический анализ является эффектом, добавленным к конструкции AST.

Обратите внимание, что тип Parse был более сложным, чем образцы Maybe и Either String; синтаксический анализатор имеет эффект отслеживания состояния, например, сколько потребляемого текста ввода и неудачный синтаксический разбор, что дало бы сообщение об ошибке. Applicative эффекты могут быть составлены вместе.