Каково практическое использование лени как встроенной функции языка? - PullRequest
11 голосов
/ 26 ноября 2011

Совершенно очевидно, почему функциональный язык программирования, который хочет быть ленивым, должен быть чистым. Я смотрю на обратный вопрос: если язык хочет быть чистым, есть ли большое преимущество в том, чтобы быть ленивым? Один из аргументов, выдвинутых одним из разработчиков Haskell, заключается в том, что он устраняет искушение; возможно, но я пытаюсь взвесить более конкретные преимущества.

Учитывая, что вы хотите заниматься функциональным программированием, в каких случаях использование встроенной лени позволяет вам выражать вещи более четко, просто или кратко?

Проще говоря: Почему лень так важна, что вы захотите встроить ее в язык?

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

Ответы [ 3 ]

19 голосов
/ 28 ноября 2011

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

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

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

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

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

С практической точки зрения, не-strict семантика позволяет вам легче определять абстракции управления, так как структуры управления по сути не являются строгими.На строгом языке все еще нужны места с не строгой семантикой.Например, конструкция if имеет не строгую семантику даже в строгих языках.

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

Что касается того, «кто пишет это десять раз перед обедом» - любой, кто использует Haskellдля своих проектов делает.Я думаю, что разработка неигрового проекта с использованием языка (нестрогого языка в вашем случае) - лучший способ понять его преимущества и недостатки.

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

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

  2. Подход "генерировать и искать" для решения многих задач оптимизации.На строгом языке вы должны чередовать генерацию и поиск, в Haskell вы просто создаете отдельные функции генерации и поиска, и ваш код остается синтаксически модульным, но чередуется во время выполнения.Подумайте о проблеме коммивояжера (TSP), когда вы генерируете все возможные туры, а затем ищите их, используя алгоритм ветвления и ограничения.Обратите внимание, что алгоритмы ветвления и привязки проверяют только первые города тура, генерируются только необходимые части маршрутов.У TSP есть несколько применений даже в самой чистой формулировке, таких как планирование, логистика и производство микросхем.Слегка измененный, он выглядит как подзадача во многих областях, таких как секвенирование ДНК.

  3. Ленивый код имеет немодулярный поток управления, поэтому у одной функции может быть много возможных потоков управления в зависимости от среды, в которой она выполняется. Это явление можно рассматривать как своего рода «полиморфизм потока управления», поэтому ленивыйабстракции потока управления являются более общими, чем их строгие аналоги, и стандартная библиотека функций более высокого порядка намного более полезна на ленивом языке.Подумайте о генераторах, циклах и итераторах Python: в Haskell функции списка охватывают все три варианта использования, а поток управления адаптируется к различным сценариям использования из-за лени.Он не ограничивается списками - подумайте о Data.Arrow и итераторах, ленивых и строгих версиях монады состояний и т. Д. Также обратите внимание, что немодульный поток управления является как преимуществом, так и недостатком, поскольку затрудняет рассуждения о производительности.

  4. Ленивые, возможно, бесконечные структуры данных полезны за пределами игрушечных примеров.См. Работы Конала Эллиота о запоминании функций более высокого порядка с помощью попыток.Бесконечные структуры данных появляются как бесконечные пространства поиска (см. 2), бесконечные циклы и неисчерпаемые генераторы в смысле Python (см. 3).

2 голосов
/ 28 ноября 2011

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

2 голосов
/ 27 ноября 2011

Mac OS X's Core Image - хороший практический пример ленивой оценки.

По сути, Core Image позволяет создавать ориентированный ациклический граф генераторов и фильтров изображений. На самом деле никакой оценки не происходит до последнего шага в процессе: материализации. Когда вы запрашиваете материализацию графа базового изображения, окончательный кадр изображения распространяется в обратном направлении через преобразования графа, таким образом сводя к минимуму количество фактических значений пикселей, которые необходимо оценить.

...