В чем смысл концепции Эффект в Эффективное прикладное программирование?Что такое аппликативные эффекты?
Например, какие части выражений приведены ниже: ?
[(+1)] <*> [2,3]
Just (+1) <*> Nothing
В чем смысл концепции Эффект в Эффективное прикладное программирование?Что такое аппликативные эффекты?
Например, какие части выражений приведены ниже: ?
[(+1)] <*> [2,3]
Just (+1) <*> Nothing
Много путаницы было вызвано неудачным выбором имен, как это довольно часто встречается в 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
возможность отказа - эффект.
Мне нравится ваше объяснение, где «чисто» получил свое имя. –
@MichaelSteele, о чем говорится в статье: «Мы собираем значения некоторых эффективных вычислений, которые затем будем использовать в качестве аргументов чистой функции' (:) '* *. –
В мире FP, эффект любого типа конструктора, таких как Maybe
, []
, IO
и т.д. эффекты не следует путать с побочными эффектами. Интуитивно, эффект является дополнительным свойством ценности, которую вы вычисляете. Maybe Int
означает, что ваша программа вычисляет Int
с эффектом сбоя, или [Int]
означает, что ваша программа вычисляет Int
, но с недетерминированным эффектом (здесь определяется недетерминированный результат как список возможных результатов).
Отправляясь отсюда, у нас есть условия аппликативных эффектов и монадических эффекты, которые означают, что указанные эффекты имеют Applicative
и Monad
экземпляров.
Я не могу найти никакой авторитетной информации для этого, это то, что я почерпнул из своего опыта.
'[]' сам по себе не является эффектом, '([], pure :: a -> [a], (<*>) :: [a-> b] -> [a] -> [b])' является эффектом, учитывая некоторые реализации 'pure' и' (<*>) '. –
@WillNess Почему вы называете это просто эффектом, а не эффектом _applicative_? По моему опыту, любой тип конструктора вида '* -> *' называется эффектом без упоминания «Аппликативный» или «Монад». –
«Применимость» подразумевается здесь. :) Я имел в виду «эффект», как в контексте этого вопроса о применении. Без 'pure' и' <*> '(или' return' и '>> =') в виду, что * является * эффектом '[]'? –
Можно сказать, что эффект типа 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
генерирует эффективные вычисления из чистого значения, которое имеет хорошее математическое кольцо для него - то есть это определение, вероятно, будет проще использовать при точном настройке.
'pure x' не является чистым, это' x', что является чистым. 'pure x' всегда является эффективным« х », по определению. 'pure (+1) :: [(Num a) => a-> a]' - эффективная функция приращения - a * недетерминированная * функция приращения. Подразумеваемый недетерминизм * есть * эффект. –
Я попытался объяснить больше, что я имел в виду, в моем ответе. Конечно, все зависит от нашего POV: мы можем видеть вещи в терминах 'concatMap', а сам Haskell полностью детерминирован, конечно, но иногда мы предпочитаем думать в терминах недетерминированного применения. Важно также не смешивать эффекты и побочные эффекты, как указывает [еще один ответ ниже] (http://stackoverflow.com/a/25838314/849891). –
Эффективное прикладное программирование можно рассматривать как принятие регулярных неэффективных вычислений и добавление эффектов к ним. Они реализованы как Applicative
экземпляров. Таким образом, хотя Int
является обычным значением, A Int
является Int
с некоторым эффектом A
и A
является примером Applicative
.
Рассмотрим это выражение:
x + y :: Int
Это выражение не является effectful; он имеет дело только с регулярными, равными значениями, так сказать. Но мы можем также иметь эффектно дополнение.
Один из способов отказ; вычисление может потерпеть неудачу или преуспеть. Если это не удается, то вычисление прекращается. Это просто тип Maybe
.
Just (+1) <*> Nothing :: Maybe Int
Кроме обычных значений, вы просто добавляете числа вместе. Но теперь у нас есть дополнение, которое может сбой. Поэтому мы должны добавить числа вместе при условии, что вычисление не сработало. В этом выражении мы видим, что вычисление не будет выполнено, поскольку второй операнд равен Nothing
.
Если ваши вычисления могут завершиться с ошибкой не только по одной причине, возможно, вы захотите иметь сообщения об ошибках, сообщающие о произошедшем сбое. Тогда вы можете использовать error эффект, который может быть представлен как что-то вроде Either String
(String
- тип сообщения об ошибке). Реализация этого Applicative
ведет себя аналогично Maybe
Applicative
.
Другим примером эффекта является синтаксический анализ. Анализ может быть реализован путем использования конструкторов и обеспечения их эффективности. Предположим, вы хотите реализовать простой арифметический язык с добавлением и умножением. Это может быть ваше абстрактное синтаксическое дерево (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
эффекты могут быть составлены вместе.
Я сомневаюсь, что эти термины используются в стандарте Haskell. Возможно, было бы полезно услышать/прочитать их в том контексте, который у вас есть. – Shoe
Те показывают типичное использование аппликативных функторов в регулярных чистых вычислениях. Может быть, взглянуть на них в контексте событий реального мира. –