Haskell:как отличаются нестрогие и ленивые?


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

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

Нестрогий Def:

функция f называется строгим, если применяется к бесконечной выражение, оно также не завершается. Другими словами, f строго если значение f bot равно /. Для большинства языков программирования, все функции строги. Но это не так Хаскель. Как простой например, рассмотрим const1, функцию константы 1, определяемую:

const1 x = 1

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

-Нежное Введение В Haskell: Функции

мне очень нравится это определение. Кажется, это лучшее, что я мог найти для понимания строгого. Это const1 x = 1 ленивый, а?

нестрогость означает, что сокращение (математический термин для оценка) исходит извне в,

так что если у вас есть (a+(bc)) тогда сначала вы уменьшаете+, затем вы уменьшаете этот внутренний (бc).

-Haskell Wiki: Лави против нестрогого

Haskell Wiki действительно смущает меня. Я понимаю, что они говорят о порядке, но я не понимаю, как (a+(b*c)) оценивал бы не строго, если бы это был pass _|_?

при нестрогом вычислении аргументы функции не вычисляются если они фактически не используются в оценке тела функции.

Под Церковь кодирование, ленивая оценка операторов сопоставляется с нестрогими оценка функций; по этой причине нестрогая оценка является часто упоминается как"ленивый". Логические выражения во многих языках форма нестрогой оценки называется оценкой короткого замыкания, где оценка возвращается, как только можно определить, что однозначный Логическое значение приведет - например, к дизъюнктивному выражению, где правда встречаются, или в выражении присоединительных где ложь встречаются и так далее. Условные выражения также обычно используют ленивая оценка, где оценка возвращается, как только однозначная ответвление приведет.

-Википедия: Стратегия Оценки

Lazy Def:

ленивая оценка, с другой стороны, означает только оценку выражение, когда его результаты необходимы (обратите внимание на сдвиг от "сокращение" до "оценка"). Поэтому, когда механизм оценки видит выражение он строит структуру данных thunk, содержащую любые значения необходимы для вычисления выражения, плюс указатель на самовыражение. Когда результат действительно необходим оценка движок вызывает выражение, а затем заменяет thunk на результат для дальнейшего использования. ...

очевидно, что существует сильное соответствие между thunk и a частично оцененное выражение. Отсюда в большинстве случаев термины "ленивый" и "нестрогие" - это синонимы. Но не совсем.

-Haskell Wiki: Лави против нестрогого

это похоже на Haskell конкретный ответ. Я так понимаю лень означает, преобразователи и нестрогом подразумевает частичную оценку. Это сравнение слишком упрощено? Делает лень всегда означают удары и нестрогом всегда означает частичную оценку.

в теории языка программирования, ленив или звоните по необходимости1 is стратегия оценки, которая задерживает оценку выражения пока его значение фактически не требуется (нестрогая оценка), а также избегайте повторных оценок (обмена).

-Википедия: Ленивая Оценка

Императив Примеры

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

Короткое Замыкание

f1() || f2()

C#, Python и другие языки с "yield"

public static IEnumerable Power(int number, int exponent)
{
    int counter = 0;
    int result = 1;
    while (counter++ < exponent)
    {
        result = result * number;
        yield return result;
    }
}

-MSDN: выход (c#)

обратные вызовы

int f1() { return 1;}
int f2() { return 2;}

int lazy(int (*cb1)(), int (*cb2)() , int x) {
    if (x == 0)
        return cb1();
    else
        return cb2();
}

int eager(int e1, int e2, int x) {
    if (x == 0)
         return e1;
    else
         return e2;
}

lazy(f1, f2, x);
eager(f1(), f2(), x);

вопросы

Я знаю, что ответ прямо передо мной со всеми этими ресурсами, но я не могу понять его. Все это кажется, что определение слишком легко отклоняется как подразумеваемое или очевидное.

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

  • и const1 x = 1 тоже ленивый?
  • как оценивается от "внутреннего" нестрогого? Это потому, что inward позволяет сокращать ненужные выражения, как в const1 x = 1? Сокращения, по-видимому, соответствуют определению ленивый.
  • тут лень всегда означает thunks и нестрогом всегда означает частичное оценке? Это просто обобщение?
  • являются ли следующие императивные понятия ленивыми, нестрогими, обоими или ни тем, ни другим?
    • Короткое Замыкание
    • через выход
    • передача обратных вызовов для задержки или предотвращения выполнения
  • и лень подмножество нестрогом или наоборот, или они взаимоисключающие. Например можно ли быть нестрогом без лень или лень без нестрогом?
  • не строгость Хаскелла достигается ленью?

спасибо Вам большое!

5 58

5 ответов:

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

нестрогом относится к семантика: математическое значение выражения. Мир, к которому применяется нестрогий, не имеет понятия о времени выполнения функции, потреблении памяти или даже компьютера. Он просто рассказывает о том, какие виды значений в домене карте, какие ценности в Йодомарин. В частности, строго функция должна сопоставить значение ⊥ ("внизу" - см. ссылку семантики выше для получения дополнительной информации об этом) с ⊥; нестрогая функция может этого не делать.

лень относится к операционному поведению: способ выполнения кода на реальном компьютере. Большинство программистов думают о программах оперативно, так что это, вероятно, то, что вы думаете. Ленивая оценка относится к реализации с использованием thunks -- указателей на код, которые заменяются значением первым раз они исполняются. Обратите внимание на несемантические слова здесь:" указатель"," первый раз","выполнено".

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

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

пример для модели оценки, то есть ни строго, ни ленивый:оптимистичные оценки, что дает некоторое ускорение, поскольку он может избежать много "легких" ударов:

оптимистическая оценка означает, что даже если подвыражение может не понадобиться для оценки сверхвыражения, мы все равно оцениваем некоторые из них, используя некоторые эвристики. Если подвыражение не завершается достаточно быстро, мы приостанавливаем его оценку до тех пор, пока оно не будет действительно нуждаться. Это дает нам преимущество перед ленивой оценкой, если подвыражение необходимо позже, так как нам не нужно генерировать thunk. С другой стороны, мы не теряем слишком много, если выражение не завершается, так как мы можем прервать его достаточно быстро.

Как вы можете видеть, эта модель оценки не строгий: если что-то, что дает _|_ оценивается, но не требуется, функция все равно завершится, так как двигатель прерывает оценку. С другой стороны, возможно, что вычисляется больше выражений, чем необходимо, поэтому это не полностью лень.

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

одно главное отличие когда условия оцениваются. Существует несколько стратегий для этого, начиная от "как можно скорее" до "только в последний момент". Термин нетерпеливой оценке иногда используется для стратегий, склоняющихся к первому, в то время как ленивый оценке правильно относится к семейству стратегий, сильно склоняющихся к последнему. Различие между "ленивой оценкой" и связанными с ней стратегиями, как правило, связано с тем, когда и где результат оценки чего-то сохраняется, а не отбрасывается в сторону. На этом основан знакомый метод запоминания в Haskell присвоения имени структуре данных и индексирования в нее. Напротив, язык, который просто склеивает выражения друг с другом (как в оценке "вызов по имени"), может не поддерживать этот.

другое различие -какие условия оцениваются, начиная от "абсолютно все" до "как можно меньше". Поскольку любое значение, фактически используемое для вычисления конечного результата, не может быть проигнорировано, разница здесь заключается в том, сколько лишних терминов оценивается. Помимо сокращения объема работы, которую должна выполнять программа, игнорирование неиспользуемых терминов означает, что любые ошибки, которые они могли бы создать, не возникнут. Когда проводится различие, требовательность относится к свойству оценки всего рассматриваемого (в случае строгой функции, например, это означает термины, к которым она применяется. Это не обязательно означают вложенные выражения внутри аргументов), в то время как нестрогом означает оценку только некоторых вещей (либо путем задержки оценки, либо путем полного отбрасывания терминов).

должно быть легко увидеть, как они взаимодействуют сложными способами; решения не являются вообще ортогональны, так как крайности имеют тенденцию быть несовместимыми. Например:

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

  • очень строгая оценка делает не-рвение несколько неуместным; если вы оцениваете все, то решение , когда сделать это менее значимо.

альтернативный однако определения существуют. Например, по крайней мере в Haskell "строгая функция" часто определяется как та, которая заставляет свои аргументы достаточно, чтобы функция оценивалась в / всякий раз, когда какой-либо аргумент делает; обратите внимание, что по этому определению,id строго (в тривиальном смысле), потому что форсирование результата id x будет иметь точно такое же поведение, как и принуждение .

Это началось как обновление, но он начал получать долго.

лень / вызов-по-необходимости - это записанная версия вызова по имени, где, если аргумент функции вычисляется, это значение сохраняется для последующего использования. В" чистой " (без эффекта) настройке это дает те же результаты, что и вызов по имени; когда аргумент функции используется два или более раз, вызов по необходимости почти всегда быстрее.
Императив Пример - видимо это возможно. Есть интересная статья о Ленивые Императивные Языки. Он говорит, что есть два метода. Один требует закрытия второй использует сокращения графика. Поскольку C не поддерживает замыкания, вам нужно будет явно передать аргумент вашему итератору. Вы можете обернуть структуру карты и, если значение не существует, вычислить его иначе возвращаемое значение.
Примечание: Haskell реализует это с помощью " указателей на код, которые заменяются значением первым раз они исполняются", - сказал Луки.
Это не строгий вызов по имени, но с обменом / запоминанием результатов.

Call-By-Name - при вычислении call-by-name аргументы функции не вычисляются перед вызовом функции - скорее, они подставляются непосредственно в тело функции (используя захват-избегая подстановки), а затем оставляются для вычисления всякий раз, когда они появляются в функции. Если аргумент не используется в тело функции, аргумент никогда не вычисляется; если он используется несколько раз, он повторно вычисляется каждый раз, когда он появляется.
Императив Пример: обратные вызовы
Примечание: Это не строго, как это позволяет избежать оценки, если не используется.

Нестрогом = при нестрогом вычислении аргументы функции не вычисляются, если они фактически не используются при вычислении тела функции.
императив Пример: короткое замыкание
Примечание: _ / _ кажется, это способ проверить, является ли функция нестрогой

таким образом, функция может быть нестрогой, но не ленивой. Ленивая функция всегда не является строгой. Call-By-Need частично определяется Call-By-Name, который частично определяется Нестрогом

фрагмент "Ленивые Императивные Языки"

2.1. НЕ-СТРОГИЙ Семантика против ленивой оценки мы должны сначала уточнить различие между "нестрогой семантикой"и" ленивой оценкой". Нестрогими являются те, которые указывают, что выражение не является оценивается до тех пор, пока это не понадобится примитивной операцией. Там может быть различные типы нестрогой семантики. Например, нестрогий вызовы процедур не оценивают аргументы до тех пор, пока их значения не будут требуемый. Конструкторы данных могут иметь нестрогую семантику, в которой составные данные являются собранная из недооцененных частей ленивая оценка, также называется отложенной оценки, является методом, обычно используемым для реализуйте нестрогую семантику. В разделе 4, эти два метода часто используемые для реализации ленивой оценки очень кратко суммируются.

вызов по значению, вызов по ленивому, и вызов по имени "вызов по значению" является общее имя, используемое для вызовов процедур со строгой семантикой. В вызовах с помощью valuelanguages вычисляется каждый аргумент вызова процедуры до вызов процедуры выполняется; значение передается в процедура или заключительное выражение. Другое имя для вызова по значению "нетерпеливая" оценка.Вызов по значению также известен как " прикладной порядок" вычисление, потому что все аргументы вычисляются перед функцией применяемый к ним."Позвоните ленивым "( используя терминологию Уильяма Клингера в [8]) - это имя, данное вызовам процедур, которые usenon-strict семантика. В языках с вызовом ленивыми вызовами процедур, аргументов нет evaluatedbefore подставляется в процедуру тело. Вызов по ленивой оценке также известен как " нормальный оценка "порядок", из-за порядка (от внешнего к внутреннему, слева справа) оценки выражения."Вызов по имени" - это конкретная реализация вызова lazy, используемая в Algol-60 [18]. Этот дизайнеры ofAlgol-60 предназначена для вызова по имени параметры физически подставляется в тело процедуры, заключенное в скобки и с подходящими изменениями имени, чтобы избежать конфликты, прежде чем тело было оцененный.

ВЫЗОВ ОТЛОЖЕННОЙ ПРОТИВ. Призыв нужен вызов, нужен продление вызова ленивым, вызванное наблюдением, что ленивый оценка может быть оптимизирована путем запоминания значения данного отложенное выражение, когда-то принудительное, так что значение не должно быть пересчитано, если это необходимо снова. Вызов по оценке потребности, поэтому расширяет вызов ленивыми методами, используя memoization, чтобы избежать необходимость повторной оценки. Фридман и Мудрые были среди тех ранее сообщалось о призыве по необходимости оценки, предложив "самоубийство суспензии", которые самоликвидировались при первой оценке, заменяя себя своими ценностями.

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