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

В последнее время я начал изучать Clojure, диалект языка программирования Lisp. И снова меня поразило использование лени в языках программирования. Ленивое вычисление на самом деле вполне нормальное явление в функциональном программировании. (См. Wiki.) В Clojure очень легко писать ленивые последовательности. Я покажу вам позже в этом посте. (Может, я напишу еще один пост о самом макросе lazy-seq. Посмотрим.)

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

Диапазон

Начнем с последовательности конечных чисел. Если длина детерминирована, в Python мы написали:

В Clojure:

Easy Cheesy.

Бесконечная последовательность

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

В качестве альтернативы вы можете довольно выразительно написать генератор, используя ключевое слово yield:

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

Давайте посмотрим на Clojure. Когда функция range вызывается как функция нулевой арности (без аргументов), она генерирует бесконечную последовательность чисел. Если вы не хотите взорвать Clojure REPL, не пытайтесь оценить его в своем Clojure REPL:

Вам определенно не нужно вручную создавать диапазон lazy-seq, но вот как это делается в Clojure:

Мы определяем функцию генератора чисел как функцию множественности, чтобы ее было легче запустить с нуля (см. Строку 6, где нам не нужно указывать аргумент для запуска функции.) Внутри макроса lazy-seq вы может рекурсивно вызывать саму функцию без возникновения ошибки переполнения стека.

Бесконечная треугольная числовая последовательность

Определение треугольного числа в вики:

Треугольное число n - это количество точек в треугольном расположении с n точками на стороне, и оно равно сумме n «натуральные числа от 1 до n. »

В Python продолжим работу с функцией генератора, фиксируя n в области действия генератора и получая треугольное число на каждом шаге:

В Clojure мы будем использовать lazy-seq для рекурсивной передачи нового числа n в следующий вызов:

Проверка треугольных чисел

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

В Python я напишу функцию для перебора треугольных чисел:

Однако в Clojure я бы предпочел композицию функций:

Вот как создавать и использовать ленивый код в Python и Clojure.