Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/303.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何用Python编写foldr(右折叠)生成器?_Python_Recursion_Fold - Fatal编程技术网

如何用Python编写foldr(右折叠)生成器?

如何用Python编写foldr(右折叠)生成器?,python,recursion,fold,Python,Recursion,Fold,Python的reduce是一个左折叠,这意味着它是尾部递归的,它的使用可以被巧妙地重写为一个循环。但是,Python没有用于执行正确折叠的内置函数。由于右折叠最自然地使用递归编写(Python不像函数语言那样喜欢递归),因此我对编写生成器方面的右折叠(foldr)感兴趣 如何做到这一点?非常具体地说,如何在Python2.7中实现这一点 编辑:我应该提到,foldr的一个好处是,您有时可以在无限列表上进行折叠,而不会有生吞活剥堆栈的风险。我希望看到保留此属性的答案 例如,Haskell的fol

Python的
reduce
是一个左折叠,这意味着它是尾部递归的,它的使用可以被巧妙地重写为一个循环。但是,Python没有用于执行正确折叠的内置函数。由于右折叠最自然地使用递归编写(Python不像函数语言那样喜欢递归),因此我对编写生成器方面的右折叠(
foldr
)感兴趣

如何做到这一点?非常具体地说,如何在Python2.7中实现这一点

编辑:我应该提到,
foldr
的一个好处是,您有时可以在无限列表上进行折叠,而不会有生吞活剥堆栈的风险。我希望看到保留此属性的答案

例如,Haskell的
foldr
在输入和输出方面都是惰性的,可以允许短路“阶跃”函数来处理长/无限输入:

foldr (&&) True (repeat False)  -- gives False
如果给定
itertools.repeat(某些值)
,则在输入端使用
list
/
reversed
/等的任何Python变体都将挂起

请注意,在同一示例中,Python的
reduce
由于严格性而受阻:

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

因此,python中的一个简单生成器(没有适当的错误检查):

e、 g:

与文档中的reduce实现几乎相同:

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
[编辑] 因此,纯粹作为一种思维练习,没有什么实际价值,只要你折叠的功能之间有一些合作,就有可能推迟。。。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
然后,只要函数转换为正确的类型,您就可以延迟计算,但是这对本机运算符不起作用,因此不确定这是否真的有用:

>>> 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
在无限列表中折叠
,在找到真值时返回

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

您必须捕获适当的异常,但应该知道如何迭代执行:

def foldr(a, b, l):
    if isinstance(l, Iterator):
        it = reversed(list(l))
    else:
        it = reversed(l)
    try:
       nxt = next(it)
    except StopIteration:
        return 
    c = a(nxt, b)  
    stop = object() 
    while nxt is not stop:
        yield c
        nxt = next(it, stop)
        c = a(nxt, c) if nxt is not stop else c



from operator import truediv
for c in (foldr(truediv, 1, [1, 2, 3, 4, 5, 6, 7, 8])):
    print(c)

如果要使用生成器定义函数,为什么不使用以下命令

def foldr(op, lst):
    return reduce(op, reversed(lst))

我想这就是你想要的:

def foldr(fn, seq, init):
    it = iter(seq)
    try:
        x = next(it)
    except StopIteration:
        try:
            for elem in init:
                yield elem
        except TypeError:
            yield init
    else:
        try:
            for elem in fn(x, foldr(fn, it, init)):
                yield elem
        except TypeError:
            yield fn(x, foldr(fn, it, init))

它还没有完全准备好生产,因为它会很快达到Python堆栈的极限,而且由于对
fn
的双重调用而出现的副作用函数会让人感到惊讶,但这应该足以让您有一个想法。

我想为了做到这一点,您的生成器必须
yield
生成一个
yield
s生成一个。。。。如果传递的参数是一个空列表,
yield
s初始值。。。坦白说,这听起来有点让人头疼。。。Python可以使用递归,只要它具有合理的深度,但我不能完全确定递归和生成器是否能很好地协同工作……haskell foldr的定义就是reduce,foldl将在无限列表中失败。Python的
reduce
是一个左折叠,所以它就像haskell的
foldl'
(注意素数)。是的,
foldl
及其变体将在无限列表中失败,这就是为什么人们可能希望使用正确的折叠。要理解,不幸的是,函数调用在python中并不懒惰,因此如果要将
foldr
实现为
f(x,f(x,f(x,…))
则所有函数都将立即得到评估,因此即使函数定义为say
def lor(a,b):a或b
,但
是惰性的
b
参数不是惰性的,也会在无限列表中失败。@achampion谢谢。在研究这个问题/答案的过程中,我意识到了这一点。在选择一个答案之前,我会给出更多的时间思考。如果代码> L>代码>本身就是一个生成器?@ 3NOCH,你不能逆转生成器/迭代器,所以它将取决于你认为什么是可接受的替代品?你添加一个例子,它如何在无限列表中工作?你怎么能在无限的列表上做FURDR?@那么,无限输入时会发生什么情况呢?在处理
n
元素后,foldr是否会间歇性返回或短路?如果
lst
是一个发生器呢?那么您需要对iterables进行操作<代码>l=列表(lst)
。您需要展开整个生成器才能执行foldr。
def foldr(op, lst):
    return reduce(op, reversed(lst))
def foldr(fn, seq, init):
    it = iter(seq)
    try:
        x = next(it)
    except StopIteration:
        try:
            for elem in init:
                yield elem
        except TypeError:
            yield init
    else:
        try:
            for elem in fn(x, foldr(fn, it, init)):
                yield elem
        except TypeError:
            yield fn(x, foldr(fn, it, init))