2009-10-28 103 views
5

我得到了我无法真正理解的这段代码。发电机C

当我将pow2s的g替换为map的gen结构后,我被卡住了。从那里,我看不到它如何继续追踪价值,以及它如何被储存。

代码编译并运行。

有人可以帮我理解这段代码吗?谢谢!

PS:我是学C

它是从后续的Python代码翻译:

>>> def pow2s(): 
     yield 1 
     for i in map((lambda x:2*x),pow2s()): 
     yield i 
>>> def mymap(f,iter): 
     for i in iter: 
     yield f(i) 

而且翻译的C代码:

#include <stdio.h> 
#include <stdlib.h> 

struct gen { // generic structure, the base of all generators 
    int (*next)() ; 
    int continue_from ; 
} ; 

typedef int (*fptr)() ; 

// Each iterator has 3 components: a structure, a constructor for the structure, 
// and a next function 

// map 

struct mapgen { // structure for map 
    int (*next)() ; 
    int continue_from ; // not really required, provided for compatibility 
    fptr f ; 
    struct gen *g ; 
} ; 

int map_next(struct mapgen *p) { // next function for map 
    return p->f(p->g->next(p->g)) ; 
} 

struct gen *map(fptr f, struct gen *g) { // constructor for map iterator 
    struct mapgen *p = (struct mapgen *)malloc(sizeof(struct mapgen)); 
    p->next = map_next; 
    p->continue_from = 0; 
    p->f = f; 
    p->g = g; 
    return (struct gen *)p ; 
} 


// powers of 2 

struct pow2s { // structure 
    int (*next)() ; 
    int continue_from ; 
    struct gen *g ; 
}; 

int times2(int x) { // anonymous lambda is translated into this 
    return 2*x ; 
} 

struct gen *pow2() ; // forward declaration of constructor 

int pow2next(struct pow2s * p){ // next function for iterator 
    switch(p->continue_from) { 
    case 0: 
    p->continue_from = 1; 
    return 1; 
    case 1: 
    p->g = map(times2,pow2()) ; 
    p->continue_from = 2; 
    return p->g->next(p->g) ; 
    case 2: 
    p->continue_from = 2; 
    return p->g->next(p->g) ; 
    } 
}  

struct gen * pow2() { // constructor for pow2 
    struct pow2s * p = (struct pow2s *)malloc(sizeof(struct pow2s)); 
    p->next = pow2next; 
    p->continue_from = 0; 
    return (struct gen *)p; 
} 

// in main, create an iterator and print some of its elements. 

int main() { 
    int i ; 
    struct gen * p = pow2() ; 
    for(i=0;i<10;i++) 
    printf("%d ",p->next(p)) ; 
    printf("\n"); 
} 
+1

如何在那里放置一些printf语句来查看它在做什么。 – 2009-10-28 15:04:37

+0

你能为这个算法提供一些上下文吗?也就是说你从哪里得到这段代码?它应该展示什么?等 – 2009-10-28 15:36:41

+0

我已经添加了上下文,它是从Python代码(发电机) – nubela 2009-10-28 15:55:04

回答

0

它通过不断增长的跟踪值结构mapgen实例与times2实例混合的尾部

每次调用pow2next都会添加ano它对尾巴。

这个例子的唯一价值是为了说明高级语言对我们有多少作用,以及高级概念的简单实现会如何影响你的性能。

6

的代码演示了如何通过的方式产生数
的任意序列“发电机”

发电机是像蟒蛇动态语言的流行工具,使在任意长的序列之一
迭代而不用一次分配整个序列。

跟踪发生在线路

p->next = pow2next; 
p->continue_from = 0; 

告诉p,它应该叫pow2next获得序列中
continue_from =下一个项目0以指示在seque的开始处NCE。

当你调用P->下一个(P)它将其实只是叫pow2nextp,因为它的参数。 对于第一次调用,这将简单地返回和增量continue_from到。

switch(p->continue_from) { 
case 0: 
    p->continue_from = 1; 
    return 1; 
/* ... */ 

在第二呼叫(continue_from = 2)将创建一个新的map_gen结构上的新鲜结构工作 pow2s以及使用该功能times2

case 1: 
    p->g = map(times2,pow2()) ; 
    p->continue_from = 2; 
    return p->g->next(p->g) ; 
/* ... */ 

所有后续调用经过P-> G->未来(P-> G)它采用times2map_gen检索下一个 值/新建map_gen根据需要的结构。 使用结构成员continue_from或使用返回码完成所有值跟踪。

虽然在C中展示了一个有趣的方法来生成生成器,但我必须声明这段代码会泄漏内存! 正如你可以看到它使用的malloc但它从来没有免费的他们分配新的结构。

我希望这个解释是不是即使你刚开始学习C.
如果你真的想了解发电机你可能想有一个小蟒蛇的前场混乱;)

UPDATE

正如你在你的评论中所述,没有任何发电机似乎返回值> 2
到越来越多的关键在于功能map_next

int map_next(struct mapgen *p) { 
    return p->f(p->g->next(p->g)); 
} 

这样做是什么,而不是返回一个固定,数它适用P-> F()
(在我们的情况下,函数times2()到的P-> G->下(对 - >克)结果。

这是一个递归调用。

它将继续在列表中调用map_next()每个map_gen,直到它到达最后一个。
这最后一个元件将返回一个固定值(或者或)。
随后被传递回以前的通话将适用times2()它并将结果返回到它的调用程序,这反过来将适用于它times2()并返回结果这是来电....(你明白了)。

所有这些递归调用总结并形成最终值。
如果你打印出每个pow2next()打电话,你会得到这样的结果:

/* first call */ 
    1 
pow2next: returning 1 
pow2next: returning 2 /* times2(1) */ 

    2 
pow2next: returning 1 
pow2next: returning 2 /* times2(1) */ 
pow2next: returning 4 /* times2(2) */ 

    4 
pow2next: returning 1 
pow2next: returning 2 /* times2(1) */ 
pow2next: returning 4 /* times2(2) */ 
pow2next: returning 8 /* times2(4) */ 

8 
pow2next: returning 1 
pow2next: returning 2 /* times2(1) */ 
pow2next: returning 4 /* times2(2) */ 
pow2next: returning 8 /* times2(4) */ 
pow2next: returning 16 /* times2(8) */ 

16 

/* and so on */ 

你可以看到最上面的调用的结果清楚如何传递一路回首先打电话来形成结果。

+0

翻译感谢您的明确解释。 这就是我所理解的。 创建新的pow2(), call next() - > returns 1, call next() - > p-> g = map_gen1 with fresh pow2s,return 2 * 1 call next() - > p- > g = map_gen1,返回2 * 2,使用FRESH pow2s创建map_gen2 在下一次调用时,在我看来,它会再次调用2 * 1,但似乎不是这样?我在哪一点错了? – nubela 2009-10-28 17:48:09

+0

我更新了我的答案以包含您的评论。 – Shirkrin 2009-10-29 08:59:14