你怎么模仿风格的Python在发电机你最喜欢的语言? 我发现这一个方案。 它必须是有趣的,看看其他的实现,尤其是在不具备一流的延续的语言。
Answer 1:
下面是在C ++中,模拟使用纤维发电机的例子:
产量返回迭代器本机C ++使用纤维
该“产量回报”的迭代器是被一个原因造就了语言的特点:简单。 这是通常更容易跨越整个collectionl迭代,存储到本地变量所需的所有方面,而不是各具特色跨随后检索操作保存其状态复杂,自定义的迭代器对象。
也有原始的C例程的setjmp,longjmp的实现类似的结果。
(LUA 协程与上述的方法实现的)
Answer 2:
我不会用产量都用Lisp /计划。
“产量”需要某种语言中的协同例程或延续设施。 产量的许多用途可在一个简单的功能性的方式来实现。
产量基本上与著名来从运营商。 ;-)这里,在一些地方的调用会导致不同的地方在其他一些常规,这取决于它的执行环境。 所以常规突然有多个入口,其为了在运行时确定。 对于简单的应用,这可能是好的,但我认为有关的代码会得到更难更复杂的代码的推理。
就拿方案示例中的问题链接:
(define/y (step)
(yield 1)
(yield 2)
(yield 3)
'finished)
(list (step) (step) (step))
呼叫(步骤)多次返回不同的值即可。
我只想创造一个封闭:
(define step
(let ((state '(1 2 3 finished)))
(lambda ()
(pop state))))
这打破上述功能的收率成两个不同的东西:携带状态和一个简单的函数改变的状态的变量。 国家不再含蓄编码到执行顺序。
(list (step) (step) (step))))
可以想见的产量的其他用途类似的解决方案。
与此相比,随着从Common Lisp的库系列发电机 :
(let ((x (generator (scan '(1 2 3 finished)))))
(list (next-in x)
(next-in x)
(next-in x)))
如果我们看一下这个Python的例子从另一个答案
def simpleRange(n):
for i in xrange(n):
yield i
for n in simpleRange(5):
print(n)
我们可以看到,它复制了控制结构。 无论主叫地方和发电机使用迭代控制结构。 使用闭包,我们可以摆脱发生器内使用控制结构的,通过仅提供状态转换的代码。
Answer 3:
在JavaScript 1.7+我通常只需要添加一些括号和括号。 其他的都是差不多的。 JavaScript 1.7中引入了除其他事项外Python的生成器和迭代。
生成器表达式:
# Python
(x + 1 for x in y if x > 100)
// JavaScript 1.8+
(x + 1 for (x in y) if (x > 100))
发电机
# Python
def simpleRange(n):
for i in xrange(n):
yield i
for n in simpleRange(5):
print(n)
// JavaScript 1.7+
function simpleRange(n) {
for (let i = 0; i < n; i++)
yield i;
}
for (n in simpleRange(5))
print(n);
列表/阵列内涵
# Python
[x + 1 for x in y if x > 100]
// JavaScript 1.7+
[x + 1 for (x in y) if (x > 100)]
Answer 4:
C ++,使用发电机
简单的范围生成的宣言:
$generator(range)
{
int i;
int _max;
int _min;
range(int minv, int maxv):_max(maxv),_min(minv) {}
$emit(int) // will emit int values. Start of body of the generator.
for (i = _min; i <= _max; ++i)
$yield(i);
$stop;
};
它的用法:
range r10(1,10);
for(int n; r10(n);)
printf("%d\n",n);
将输出
1
2
...
10
Answer 5:
要@dmitry_vk关于Common Lisp的答案,我想补充一点,在Lisp中,其实并不真正需要的发电机。 它们的使用情况被关闭,特殊变量和宏的不同的应用程序完全覆盖 - 而无需学习新的结构的附加概念的开销。
有时甚至是内置的结构将工作。 让我们来看看从Python维基的例子:
# add squares less than 100
from itertools import count, takewhile
sum = 0
square = (i*i for i in count())
bounded_squares = takewhile(lambda x: x < 100, square)
for i in bounded_squares:
sum += i
使用loop
可以以更直接的方式来实现:
CL-USER> (loop :for i :from 0 :while (< i 100) :sum (expt i 2))
328350
由于loop
是更灵活,比Python的for
有没有必要在这里介绍特殊的语法。
让我们考虑另一种使用情况 - 迭代过一些自定义的树。 假设树是由代表node
指点下自己的children
。
(defstruct node
data
children)
我们可以用一个相当小的和简单的宏走过去所有的树/子树。
(defmacro dotree ((var root &optional result-form) &body body)
`(block nil
(labels ((traverse (node)
(let ((,var node))
,@body
(dolist (child (children node))
(traverse child))
,result-form)))
(when-it ,root
(traverse it)))))
(注意:为了更清楚起见,我没有使用gensym
在里面,但你应该)。
下面是它的用法的例子 - 让所有的叶子节点的列表:
(let (rez)
(dotree (node tree (reverse rez))
(when (leafp node)
(push node rez))))
这看起来和工作就像标准的dolist
宏。 而且,与dolist
你可以在任何时候通过调用停止迭代, return
。
总体来说,我还没有看到发电机使用,不能在Lisp的一些不太复杂的方式来实现的实际例子。
PS你也可以看看该系列的Lisp库,在上世纪90年代实施了类似的概念,以发电机。 或CLAZY -从2000年年底的。
Answer 6:
单子可用于表示发电机(即使语义是有点不同)。
因此,任何让我们一个特殊的语法中定义的一元操作语言都可以在这里使用。
- VB.NET/C#(LINQ -但C#已经有了
yield return
) - 阶(对于-推导)
- 哈斯克尔(DO-符号)
- F#/ ocaml的(计算式/执行)
红宝石可以通过其内置的延续能力效仿发电机。
Answer 7:
Common Lisp的,虽然没有原生的延续,允许创建使用CPS变压器像分隔的延续CL-CONT 。 因此,在Common Lisp的发电机可以写在几乎相同的方式,计划发电机。
顺便说一句,基于连续的发电机有一个特点是Python和C#发电机缺乏:在yield
可能会在生成函数调用的动态范围内调用。 Python和C#发电机允许yield
放置只有一个发电机的主体内。
Answer 8:
红宝石:
发生器功能:
def simple_range(n)
Enumerator.new do |y|
(0..n).each { |v| y.yield(v) }
end
end
Answer 9:
一般yield
是在有第一类函数的语言是多余的。 例如,在TIScript你可以做发电机是这样的:
发电机。 请注意,它返回内部函数。
function range( from, to )
{
var idx = from - 1;
return function() { if( ++idx <= to ) return idx; } // yields value on call
}
而它的用法:
for( var item in range(12,24) )
stdout << item << " ";
for(elem in source)
在TIScript是从JS略有不同。 如果源是它被调用函数的返回值分配给elem
直到函数将不返回void(空函数的默认返回值)。