Что такое «pythonic», эквивалентный функции «fold» от функционального программирования?

Какой самый идиоматический способ добиться чего-то вроде следующего, в Haskell:

foldl (+) 0 [1,2,3,4,5] --> 15 

Или его эквивалент в Ruby:

 [1,2,3,4,5].inject(0) {|m,x| m + x} #> 15 

Очевидно, что Python предоставляет функцию reduce , которая представляет собой реализацию fold, точно так же, как указано выше, однако мне сказали, что «питонический» способ программирования состоит в том, чтобы избежать lambda терминов и функций более высокого порядка, предпочитая, по возможности, понимание списков. Поэтому существует ли предпочтительный способ сгибания списка или структуры списка в Python, которая не является функцией reduce , или reduce идиоматический способ достижения этого?

6 Solutions collect form web for “Что такое «pythonic», эквивалентный функции «fold» от функционального программирования?”

Питоновский способ суммирования массива – это sum . Для других целей иногда можно использовать некоторую комбинацию reduce и operator модуль, например

 def product(xs): return reduce(operator.mul, xs, 1) 

Имейте в foldl , что reduce на самом деле является foldl , в терминах Haskell. Специального синтаксиса для выполнения сгибов нет, нет встроенного foldr , и фактически использование reduce с неассоциативными операторами считается плохим.

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

Haskell

foldl (+) 0 [1,2,3,4,5]

питон

reduce(lambda a,b: a+b, [1,2,3,4,5], 0)

Очевидно, это тривиальный пример, иллюстрирующий точку. В Python вы просто делаете sum([1,2,3,4,5]) и даже пуристы Haskell обычно предпочитают sum [1,2,3,4,5] .

Для нетривиальных сценариев, когда нет очевидной удобной функции, идиоматический пифонический подход заключается в том, чтобы явно выписать цикл for и использовать переменное переменное переменное вместо использования reduce или fold .

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

В Python 3 reduce было удалено: Примечания к выпуску . Тем не менее вы можете использовать модуль functools

 import operator, functools def product(xs): return functools.reduce(operator.mul, xs, 1) 

С другой стороны, документация выражает предпочтение в отношении -loop вместо reduce , следовательно:

 def product(xs): result = 1 for i in xs: result *= i return result 

Вы также можете изобрести колесо:

 def fold(f, l, a): """ f: the function to apply l: the list to fold a: the accumulator, who is also the 'zero' on the first call """ return a if(len(l) == 0) else fold(f, l[1:], f(a, l[0])) print "Sum:", fold(lambda x, y : x+y, [1,2,3,4,5], 0) print "Any:", fold(lambda x, y : x or y, [False, True, False], False) print "All:", fold(lambda x, y : x and y, [False, True, False], True) # Prove that result can be of a different type of the list's elements print "Count(x==True):", print fold(lambda x, y : x+1 if(y) else x, [False, True, True], 0) 

Фактический ответ на эту проблему (сокращение): просто используйте цикл!

 initial_value = 0 for x in the_list: initial_value += x #or any function. 

Это будет быстрее, чем сокращение, и такие вещи, как PyPy, могут оптимизировать такие петли.

BTW, сумма случае должна быть решена с помощью функции sum

На самом деле не отвечайте на вопрос, но однострочники для foldl и foldr:

 a = [8,3,4] ## Foldl reduce(lambda x,y: x**y, a) #68719476736 ## Foldr reduce(lambda x,y: y**x, a[::-1]) #14134776518227074636666380005943348126619871175004951664972849610340958208L 
Python - лучший язык программирования в мире.