Я знаю, что вы особенно интересуетесь питоном, но я подумал, что я должен рассказать о том, как Clojure выполняет это, поскольку он решает проблему довольно элегантно и напрямую.
Clojure имеет reduced
функцию , которая возвращает версию того, что ей было передано, так что эта версия будет немедленно завершена в вызове для сокращения. Это позволяет легко сделать что-то вроде этого:
(reduce (fn [a v]
(if (< a 100)
(+ a v)
(reduced a)))
(range 20))
;; => 105
Возвращает первую сумму, которая больше или равна сотне, или наибольшую сумму, достигнутую, если ни одна из них не превышает. И стоит отметить, что он делает это без использования / итерации по всей сокращаемой коллекции, которая может быть очень большой или даже бесконечной ленивой последовательностью. Более того, это имеет определенное преимущество перед применением какой-либо операции фильтрации в первую очередь, поскольку вы можете иметь условие завершения, зависящее от создаваемого значения, а не только от уменьшения отдельных значений в коллекции.
Вы упоминаете, что эта идея кажется чем-то "анит-функциональной". Это может показаться имевшим место в python, где неясно, как бы вы достигли этого, не прибегая к некоторому грязному внешнему состоянию (или в лучшем случае альтернативной версии reduce
). Тем не менее, это работает чисто и функционально (даже чисто так) в Clojure, потому что он был встроен в язык. Ключ в том, что reduce
знает, как искать значения reduced
, и объекты могут нести эту информацию вместе с ними (либо в виде обернутого значения в виде метаданных; не уверен, какой именно ...).
Это, безусловно, удобная функция, которой я был рад, когда мне это было нужно.