2009-10-28 95 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