2009-10-28 41 views
5

Tôi nhận được đoạn mã này tôi thực sự không thể hiểu được.Máy phát điện trong C

Tôi bị kẹt sau khi thay thế g của pow2s thành cấu trúc gen của bản đồ. Và từ đó, tôi không thể thấy nó tiếp tục theo dõi giá trị như thế nào, và nó được lưu trữ như thế nào.

Mã biên dịch và chạy.

Ai đó có thể giúp tôi hiểu mã này không? Cảm ơn!

PS: Tôi đang học C

Nó được dịch từ mã theo 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) 

Và mã C dịch:

#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

Cách đặt một số câu lệnh printf vào đó để xem nó đang làm gì. –

+0

Bạn có thể cung cấp một số ngữ cảnh cho thuật toán này không? Tức là bạn lấy mã này ở đâu? Nó được cho là gì? vv –

+0

tôi đã thêm ngữ cảnh, nó được dịch từ mã python (máy phát) – nubela

Trả lời

0

Nó theo dõi các giá trị bằng cách phát triển một đuôi của các thể hiện struct mapgen được trộn lẫn với các thể hiện times2

Mỗi cuộc gọi đến pow2next thêm ano có cặp vào đuôi.

Giá trị duy nhất của ví dụ này là minh họa cho bao nhiêu ngôn ngữ cấp cao dành cho chúng tôi và cách triển khai ngây thơ các khái niệm cấp cao có thể giết hiệu suất của bạn.

6

Mã này cho biết cách bạn có thể tạo một chuỗi số tùy ý
bằng phương tiện 'máy phát điện'.

phát là một công cụ phổ biến trong các ngôn ngữ động như python và cho phép một đến
lặp qua một chuỗi dài tùy ý mà không phân bổ toàn bộ chuỗi cùng một lúc.

Các theo dõi xảy ra trong các dòng

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

Mà nói p rằng nó nên gọi pow2next để có được những mục tiếp theo trong chuỗi
continue_from = 0 để chỉ ra rằng ở nơi bắt đầu của seque nce.

Khi bạn gọi p-> tiếp theo (p) nó sẽ trong thực tế chỉ cần gọi pow2next với p vì nó là tham số. Đối với cuộc gọi đầu tiên, điều này sẽ chỉ trả về và tăng continue_from đến .

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

Trên cuộc gọi thứ hai (continue_from = 2) nó sẽ tạo ra một mới map_gen cấu làm việc trên struct tươipow2s và sử dụng các chức năng times2:

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

Tất cả các cuộc gọi tiếp tục đi qua p-> g-> tiếp theo (p-> g) trong đó sử dụng times2map_gen để lấy giá trị tiếp theo/tạo mới map_gen cấu trúc nếu cần. Tất cả theo dõi giá trị được thực hiện bằng cách sử dụng cấu trúc tiếp tục_from hoặc bằng cách sử dụng mã trả lại.

Trong khi hiển thị một cách tiếp cận thú vị cho máy phát điện trong C Tôi phải nói rằng mã này rò rỉ bộ nhớ! Như bạn có thể nhìn thấy nó phân bổ cơ cấu mới sử dụng malloc nhưng nó không bao giờ miễn phí 's chúng.

Tôi hy vọng lời giải thích này không phải là để gây nhầm lẫn ngay cả khi bạn chỉ mới bắt đầu học C.
Nếu bạn thực sự muốn hiểu máy phát điện bạn có thể muốn có một con trăn nhỏ cũ course;)

UPDATE

Như bạn đã nêu trong nhận xét không có máy phát nào có vẻ trả về giá trị> 2.
Chìa khóa để các con số tăng nằm trong hàm map_next:

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

Điều này không là, thay vì trả lại một sửa chữa, số nó áp dụng p-> f()
(

01.235 trong trường hợp của chúng tôi các chức năng times2() đến kết quả của p-> g-> tiếp theo (p-> g).

Đây là một cuộc gọi đệ quy.

Nó sẽ tiếp tục kêu gọi map_next() trên mỗi map_gen trong danh sách cho đến khi nó đạt đến người cuối cùng.
Phần tử cuối cùng này sẽ trả về giá trị cố định (hoặc hoặc).
mà sau đó được chuyển lại cho các cuộc gọi trước đó sẽ được áp dụng times2() vào nó và trả về kết quả để nó gọi, mà lần lượt sẽ áp dụng times2() vào nó và trả lại kết quả để đó là người gọi .... (bạn có ý tưởng).

Tất cả các cuộc gọi đệ quy này tổng hợp và tạo thành giá trị cuối cùng.
Nếu bạn in ra kết quả của mỗi pow2next() gọi bạn sẽ có được điều này:

/* 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 */ 

Bạn có thể thấy rõ như thế nào là kết quả của hầu hết các cuộc gọi trên được thông qua tất cả các cách trở lại cuộc gọi đầu tiên để tạo thành kết quả.

+0

Cảm ơn bạn đã giải thích rõ ràng. Đây là những gì tôi hiểu. On tạo pow2 mới(), cuộc gọi tiếp theo() -> trả về 1, cuộc gọi tiếp theo() -> p-> g = map_gen1 với pow2s tươi, trả 2 * 1 cuộc gọi tiếp theo() -> p- > g = map_gen1, trả về 2 * 2, tạo map_gen2 với FRESH pow2s Trong lần gọi tiếp theo, có vẻ như tôi sẽ gọi lại 2 * 1, nhưng có vẻ như vậy không? Tại thời điểm đó tôi đã làm sai? – nubela

+0

Tôi đã cập nhật câu trả lời của mình để bao gồm nhận xét của bạn. – Shirkrin

Các vấn đề liên quan