为什么迭代器在 Python 文档中被认为是函数式的?

Why iterator is considered functional-style in the Python documentation?

我正在尝试了解迭代器。我注意到 Python documentation 认为迭代器是一种函数式结构。不是很懂

迭代器里面不是有状态吗。所以当你调用 it.__next__() 时,你改变了迭代器的状态。据我所知,对象的变异状态不被认为是函数式的,因为函数式编程强调 object/closure.

的不变性和可组合性

实际上,问题的出现是因为我想写一个 Scheme procedure/function 它接受令牌和 return 一个迭代器。

(define tokens->iterator
  (lambda ls
    (lambda ()
      (if (null? ls)
          '*eoi*
          (let ((tok (car ls)))
            (set! ls (cdr ls))
            tok)))))

注意我必须使用 set! 来变异 ls,这就是我想出这个问题的方式。

要使用它,

(define it (tokens->iterator 1 '+ 2))

为了测试它,

scheme@(guile-user)> (it)
 = 1
scheme@(guile-user)> (it)
 = +
scheme@(guile-user)> (it)
 = 2
scheme@(guile-user)> (it)
 = *eoi*
scheme@(guile-user)> (it)
 = *eoi*

为了好玩,我也把这个翻译成Python:

def tokens_to_iterator(*tup):
    ls = list(tup)
    def iterator():
        if not ls:
            return "*eoi*"
        else:
            tok = ls.pop(0)
            return tok
    return iterator

类似地,pop() 方法通过改变列表删除并 return 第一个元素。

要使用它,

it = tokens_to_iterator(1, "+", 2)

为了测试它,

>>> it()
1
>>> it()
'+'
>>> it()
2
>>> it()
'*eoi*'
>>> it()
'*eoi*'

谁能澄清一下?顺便说一句,我正在使用 Python 3 和 Guile Scheme,以防有人有兴趣尝试这些示例。

你说得很好。迭代器当然不是 "purely functional," 这个经常用来描述完全不使用变异的习语的术语。不过,更广泛的术语 "functional," 的定义更为宽松,以表示使用相对较少变异的程序,这些程序使用高阶和第一个 class 函数,也许最广泛的是,"use weird abstractions that don't look like C."

我认为,坦率地说,我不会称迭代器为函数式。那就是:我同意你的看法。

函数式 风格 是将数据列表作为一个整体来处理,而不是您可以随心所欲更改的值集合。例如,如果你有一个数字列表,你想改变第 3 个元素,非功能性的方法是直接改变它:

>>> lst = ["a", "b", "c", "d", "e"]
>>> lst[3] = "Z"
>>> lst
["a", "b", "c", "Z", "e"]

函数式方法是编写一个函数,该函数采用原始序列和return经过更改的新列表,保持原始序列不变。

>>> lst = ["a", "b", "c", "d", "e"]
>>> new_lst = [x if i != 3 else "Z" for (i, x) in enumerate(lst)]
>>> lst
["a", "b", "c", "d", "e"]
>>> new_lst
["a", "b", "c", "Z", "e"]

你的迭代器都不是纯功能的,因为它们确实保持可变状态,虽然被视为黑盒子,但你可以在功能上使用它们,因为迭代器的 user 不能影响它直接说。

一个纯函数迭代器是一个函数,它将列表当前状态作为输入,return一个值 传递给下一次函数调用的新状态。

>>> state = 0
>>> def it(lst, state):
...   if state is None:
...       return None
...   return lst[state], state + 1
...
>>> lst = ["a", "b", "c", "d", "e"]
>>> value, new_state = it(lst, state)
>>> value
'a'
>>> state, new_state
(0, 1)
>>> it(lst, new_state)
('b', 2)
>>> state, new_state
(0, 1)