另一种方法是使用泛型函数unfold
def unfold (f, acc):
return f ( lambda x, next: [x] + unfold (f, next)
, lambda x: [x]
, acc
)
def main (ones):
def value (i):
return 1 if i in ones else 0
return unfold ( lambda next, done, i:
done (value (i)) if i >= 10 else next (value (i), i + 1)
, 0
)
print (main ( { 2, 5 }))
# [0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0]
unfold 可以以有趣的方式使用
def alphabet ():
return unfold ( lambda next, done, c:
done (c)
if c == 'z' else
next (c, chr (ord (c) + 1))
, 'a'
)
print (alphabet ())
# ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']
Python 的 lambda 语法非常僵化,其笨拙的三元语法使函数表达式难以编写。在下面的示例中,我们使用一些命令式语法预先定义了一个函数 gen 以提高可读性,然后我们将其传递给 unfold - 该程序还表明 state 可以是一个复杂的值
def fib (n):
def gen (next, done, state):
(n, a, b) = state
if n == 0:
return done (a)
else:
return next (a, (n - 1, b, a + b))
return unfold (gen, (n, 0, 1))
print (fib (20))
# [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765]
当然,所有这些痛苦的存在都是有原因的——这是一个信号,表明我们做错了什么。一个经验丰富的 python 程序员永远不会像我们上面那样写main、alphabet 或fib。所以它不是 pythonic(正如他们所说),而是 functional,希望能回答你的问题。
下面,我们极大地简化了unfold - 我们不是将next 和done 帮助器传递给用户lambda,而是要求用户返回一个对其选择进行编码的元组:(value, None) 说value 是序列中的最后一个值,(value, nextState) 将产生下一个值并继续下一个状态。
这里的权衡是unfold 不那么复杂,但它需要用户知道特殊的元组信令来编写他们的程序。之前,next 和done 让用户无需担心这种担忧。无论哪种方式都可以,我分享这个只是为了提供另一种选择
def unfold (f, acc):
(x, nextAcc) = f (acc)
if nextAcc is None:
return [x]
else:
return [x] + unfold (f, nextAcc)
def fib (n):
def gen (state):
(n, a, b) = state
if n == 0:
return (a, None)
else:
return (a, (n - 1, b, a + b))
return unfold (gen, (n, 0, 1))
print (fib (20))
# [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765]