Python是否具有一阶递归关系的迭代递归生成器函数?

Python是否具有一阶递归关系的迭代递归生成器函数?,python,recursion,itertools,recurrence,functools,Python,Recursion,Itertools,Recurrence,Functools,是否有一个内置函数或标准库函数大致相当于 def recur_until(start, step_fu, stop_predicate=lambda _: False): current = start while not stop_predicate(current): yield current current = step_fu(current) 或 甚至只是 def recur(start, step_fu): current =

是否有一个内置函数或标准库函数大致相当于

def recur_until(start, step_fu, stop_predicate=lambda _: False):
    current = start
    while not stop_predicate(current):
        yield current
        current = step_fu(current)

甚至只是

def recur(start, step_fu):
    current = start
    while True:
        yield current
        current = step_fu(current)
在任何版本的Python中?(后者与其他两个结合使用时效果相同。)

这样的生成器函数允许迭代计算某些递归定义的序列,即一阶递归关系

虽然在需要时实现这些并不太困难,但我觉得它们应该是其中的一部分,但如果是的话,我还无法在文档中找到它


用法示例: 还应使用非数字元素:

list(recur_until('', lambda x: '[{}]({})'.format(x, len(x)), lambda x: len(x) > 30))
# ['',
#  '[](0)',
#  '[[](0)](5)',
#  '[[[](0)](5)](10)',
#  '[[[[](0)](5)](10)](16)',
#  '[[[[[](0)](5)](10)](16)](22)']

缺少的一点是,您需要一些东西来将递归步进函数转换为生成器。一旦你有了它,你就可以使用任何一种itertools方法

def recur_to_gen(step_fu, current, sentinel=None):
    while current != sentinel:
        yield current
        current = step_fu(current)


matches = itertools.takewhile(predicate, recur_to_gen(step_fu, start))
recurr\u\u\u gen
itertools

添加软件包提供了模拟这一点的部分,这可能是一个合理的建议

from functional import dropWhile, iterate    
recur = dropWhile(predicate, iterate(step_func, start))
比如说,

>>> next(dropWhile(lambda x : x < 10, iterate(lambda x: x + 1, 2)))
10
>>>下一步(dropWhile(lambda x:x<10,迭代(lambda x:x+1,2)))
10
dropWhile
itertools.dropWhile
)在Python3.3+中,新工具可以与其他itertools一起用于此目的

例如:

>>> from itertools import accumulate, repeat, takewhile
>>> fun = accumulate(range(2, 10), lambda x, _: x**2 - 1)
>>> list(fun)
[2, 3, 8, 63, 3968, 15745023, 247905749270528, 61457260521381894004129398783]
>>> fun = takewhile(lambda y: y < 1e4, accumulate(repeat(2), lambda x, _: x**2 - 1))
>>> list(fun)
[2, 3, 8, 63, 3968]
>>从itertools导入累积、重复、提取
>>>乐趣=累积(范围(2,10),λx,x**2-1)
>>>列表(乐趣)
[2, 3, 8, 63, 3968, 15745023, 247905749270528, 61457260521381894004129398783]
>>>乐趣=takewhile(λy:y<1e4,累加(重复(2),λx,x**2-1))
>>>列表(乐趣)
[2, 3, 8, 63, 3968]
accumulate
接受一个序列和一个具有两个参数的函数:第一个是累积值,第二个是序列中的下一个值。在这种情况下,我们只需要第一个参数,它将是传递函数的第一次调用传递给
acculate
的序列的第一个元素,以及后续调用该函数的返回值


因此,在这种情况下,我们只需要将传递序列的开头作为初始值-
2
。序列其余部分的内容是不相关的,但我们可以使用它的长度来控制需要多少元素(如第一个示例)或创建一个无限生成器(如第二个示例)。

即,相当于Haskell的
iterate
函数
iterate(\x->x+1)0=0,1,2,3,4,5,…
@chepner
iterate
结合
takeWhile
。我永远不知道如何处理那些仅仅是“x存在吗?”的问题,我相信答案是“不存在”。除了链接到您已经链接的文档之外,我无法证明这个答案的正确性。@SvenMarnach True。我一直在关注itertools中缺少的部分,但是你确实需要结合
迭代
{take,drop}而
@DSM,是的,我知道存在问题的问题是否定答案基本上是不可证明的。但是,由于我特别感兴趣的是标准库在这里提供了什么,我不知道如何用不同的方式来表达我的问题。它通常被称为
iterate
,例如在Haskell中或在this中。不幸的是,我认为Python中的“iterate”与
iter
,这更多的是关于单步执行序列,而不是递归地对一个项应用步进函数来获取下一个项。但是无论用什么名字,我认为
itertools
都是这样的东西的好家。@StefanPochmann函数
recurr\u to\u gen()
是一个生成器函数(因为它
yield
s)。这里没有生成器表达式。@SvenMarnach:我想SP是在提请注意PM的第一句话——OP的原始函数(尽管称为
recur
)是非递归的,并且已经是一个genfunc了。@DSM-从调用自身的意义上讲不是递归的,但是,它通过对当前项调用步进函数来迭代不一定是连续的项链,以获得下一个项。Python的一个较新的功能包:它仍然有效(通过
pip
安装,但我没有对它进行广泛测试),但是是的,我认为
functional
是一个一次性的概念验证,从未真正得到支持。嘿,在看到您的答案之前不久,我刚刚启动了另一台装有Python3.4的计算机来测试类似的东西。
>>> next(dropWhile(lambda x : x < 10, iterate(lambda x: x + 1, 2)))
10
>>> from itertools import accumulate, repeat, takewhile
>>> fun = accumulate(range(2, 10), lambda x, _: x**2 - 1)
>>> list(fun)
[2, 3, 8, 63, 3968, 15745023, 247905749270528, 61457260521381894004129398783]
>>> fun = takewhile(lambda y: y < 1e4, accumulate(repeat(2), lambda x, _: x**2 - 1))
>>> list(fun)
[2, 3, 8, 63, 3968]