如何在Python中编写foldr(正确折叠)生成器?

编程入门 行业动态 更新时间:2024-10-27 14:25:16
本文介绍了如何在Python中编写foldr(正确折叠)生成器?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述

Python的 reduce 是向左折叠的,这意味着它是尾递归的,并且其用法可以整齐地重写为循环.但是,Python没有内置的函数可以进行正确的折叠.由于右折最自然地是用递归编写的(Python不像函数语言那样喜欢递归),所以我对用生成器编写右折( folder )感兴趣.

Python's reduce is a left-fold, which means it is tail-recursive and its uses can be neatly rewritten as a loop. However, Python does not have a built-in function for doing right folds. Since right-folds are most naturally written with recursion (and Python doesn't like recursion as much as functional languages), I'm interested in writing a right fold (foldr) in terms of a generator.

这怎么办?而且非常具体地讲,如何在Python 2.7中完成?

How can this be done? And very specifically, how can it be done in Python 2.7?

我应该提到 folder 的好处之一是,您有时可以在无限列表上进行折叠,而不会冒着吞噬您的堆栈的风险.我希望看到保留此属性的答案.

I should have mentioned that one of the benefits to foldr is that you can sometimes fold on infinite lists without risk of eating your stack alive. I would like to see answers that preserve this property.

例如,Haskell的 folder 在输入和输出上都是惰性的,并且可以使短路的步进"功能在长/无限输入上起作用:

For example, Haskell's foldr is lazy on both input and output and can allow for short-circuiting "step" functions to work on long/infinite inputs:

foldr (&&) True (repeat False) -- gives False

任何使用 list / reversed /etc的Python变体.如果指定了 itertools.repeat(some_value),则输入中的内容将挂起.

Any Python variant that uses list/reversed/etc. on the input will hang if given itertools.repeat(some_value).

请注意,由于严格性,在同一示例中Python的 reduce 令人窒息:

Note that Python's reduce chokes in the same example because of strictness:

reduce(lambda x, y: x and y, itertools.repeat(False), True) # hangs

推荐答案

所以是python中的简单生成器(没有适当的错误检查):

So a simple generator in python (without appropriate error checking):

def foldr(op, lst): l, x = reversed(list(lst)), None for i in l: if not x: x = i continue x = op(x, i) yield x

例如:

>>> from operator import mul >>> for i in foldr(mul, [1,2,3,4]): ... print i 24 24 12

与文档中的reduce的大致等效"实现几乎相同:

Almost identical to the 'roughly equivalent' implementation of reduce in the documentation:

def foldr(function, iterable, initializer=None): it = reversed(list(iterable)) if initializer is None: try: initializer = next(it) except StopIteration: raise TypeError('foldr() of empty sequence with no initial value') accum_value = initializer for x in it: accum_value = function(accum_value, x) yield accum_value

因此,纯粹是一种锻炼,几乎没有实用价值,只要您折叠的功能之间存在某种协作,就可以推迟...例如:

So purely as an exercise of the mind and with very little practical value, it is possible to defer as long as there is some cooperation between the function that you a folding over... e.g.:

class Defer(object): def __init__(self, func, *args): self.func = func self.args = args def __bool__(self): return self.func(*self.args) def __int__(self): return self.func(*self.args) def foldr(function, iterable, initializer): it = iter(iterable) try: return function(next(it), Defer(foldr, function, it, initializer)) except StopIteration: return initializer

然后,只要函数转换为正确的类型,您就可以推迟计算,但是这不适用于本机运算符,因此不确定此函数的实际用途是什么:

Then as long as the function converts to the right type you can defer the calculation, however this will not work with native operators, so not sure how useful this really is:

>>> print(foldr(lambda a, b: int(a)*int(b), [1,2,3,4], 1)) 24

定义一个永久生成器:

from itertools import repeat def forever(): yield False yield True for i in repeat(False): yield i

将或折叠到无限列表中,当找到True时返回

Folding or across an infinite list, returns when it finds a True

>>> print(foldr(lambda a, b: bool(a) or bool(b), forever(), False)) True

更多推荐

如何在Python中编写foldr(正确折叠)生成器?

本文发布于:2023-11-10 09:19:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1574978.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:生成器   正确   如何在   foldr   Python

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!