我试图理解迭代器。我注意到Python documentation认为迭代器是一个功能样式的构造。我真的不明白。
迭代器内部是否有状态是不是真的。所以当你调用it.__next__()
时,你会改变迭代器的状态。据我所知,对象的变异状态不被认为是功能性的,因为函数式编程强调对象/闭包的不变性和组合能力。
实际上,问题出现了,因为我想编写一个Scheme过程/函数来获取标记并返回一个迭代器。
(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)
$2 = 1
scheme@(guile-user)> (it)
$3 = +
scheme@(guile-user)> (it)
$4 = 2
scheme@(guile-user)> (it)
$5 = *eoi*
scheme@(guile-user)> (it)
$6 = *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()方法通过改变列表来删除并返回第一个元素。
要使用它,
it = tokens_to_iterator(1, "+", 2)
要测试它,
>>> it()
1
>>> it()
'+'
>>> it()
2
>>> it()
'*eoi*'
>>> it()
'*eoi*'
有人可以澄清一下吗?顺便说一句,我正在使用Python 3和Guile Scheme,以防任何人有兴趣尝试这些例子。
答案 0 :(得分:8)
你有一个很好的观点。迭代器肯定不是"纯功能,"该术语通常用于描述完全不使用突变的习语。更广泛的术语"功能性,"但是,更宽松的定义是指示使用相对较少的突变的程序,使用高阶和一等函数,或许最广泛的,"使用看起来不像的奇怪的抽象C"
坦率地说,我认为我不调用迭代器功能。那就是:我同意你的看法。
答案 1 :(得分:3)
功能样式用于处理整个数据列表,而不是可以随心所欲地更改的值集合。例如,如果您有一个数字列表,并且想要更改第三个元素,那么非功能性方法是直接更改它:
>>> lst = ["a", "b", "c", "d", "e"]
>>> lst[3] = "Z"
>>> lst
["a", "b", "c", "Z", "e"]
功能方法是编写一个函数,该函数接受原始序列并返回一个包含所做更改的新列表,使原始序列保持不变。
>>> 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 不能直接影响那个状态。
纯函数迭代器将是一个函数,它将列表和作为输入作为当前状态,并返回一个值和一个新状态传递给下一个调用函数。
>>> 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)