【发布时间】:2015-03-31 15:54:19
【问题描述】:
Python 的reduce 是左折叠的,这意味着它是尾递归的,它的用途可以巧妙地重写为循环。但是,Python 没有用于进行正确折叠的内置函数。由于右折叠最自然地是用递归编写的(而且 Python 不像函数式语言那样喜欢递归),所以我有兴趣在生成器方面编写右折叠 (foldr)。
如何做到这一点?更具体地说,如何在 Python 2.7 中完成?
编辑:我应该提到foldr 的好处之一是你有时可以在无限列表中弃牌,而不会冒着吃掉你的筹码的风险。我希望看到保留此属性的答案。
例如,Haskell 的 foldr 在输入和输出上都是惰性的,并且可以允许短路“步进”函数在长/无限输入上工作:
foldr (&&) True (repeat False) -- gives False
任何使用list/reversed/等的Python变体。如果给定itertools.repeat(some_value),输入将挂起。
请注意,由于严格性,Python 的 reduce 在同一示例中阻塞:
reduce(lambda x, y: x and y, itertools.repeat(False), True) # hangs
【问题讨论】:
-
我认为为了做到这一点,你的生成器必须
yield一个生成器yields一个生成器......如果传递的参数是一个空列表,yields 初始值......坦率地说,这听起来有点让人头疼...... Python 可以很好地使用递归,只要它具有合理的深度,但我不完全确定递归和生成器可以很好地协同工作。 .. -
haskell foldr的定义只是reduce,foldl在无限列表上会失败。
-
Python 的
reduce是左折叠的,所以它就像 Haskell 的foldl'(注意素数)。是的,foldl及其变体将在无限列表中失败,这就是为什么人们可能希望使用正确的折叠。 -
明白了,不幸的是,函数调用在 python 中并不懒惰,所以如果你将
foldr实现为f(x, f(x, f(x, ....))),那么所有函数都将立即得到评估,因此即使函数在无限列表中也会失败被定义为def lor(a,b): a or b,而or是惰性的,b参数不是。 -
@achampion 谢谢。在处理这个问题/答案的过程中,我意识到这一点。在选择答案之前,我会花更多时间思考。