2012-08-22 78 views
2

我已經寫了一些Go代碼在FP風格生成素數:爲什麼這個代碼失敗?

package main 
import (
    "fmt" 
) 

func gen_number_stream() func() (int, bool) { 
    i := 1 
    return func() (int, bool) { 
     i += 1 
     return i, true 
    } 
} 

func filter_stream(stream func() (int, bool), f func(int) bool) func() (int, bool) { 
    return func() (int, bool) { 
     for i, ok := stream(); ok; i, ok = stream() { 
      if f(i) { 
       return i, true 
      } 
     } 
    return 0, false 
    } 
} 

func sieve(stream func() (int, bool)) func() (int, bool) { 
    return func() (int, bool) { 
     if p, ok := stream(); ok { 
      remaining := filter_stream(stream, func(q int) bool { return q % p != 0 }) 
      stream = sieve(remaining) 
      return p, true 
     } 
     return 0, false 
    } 
} 


func take(stream func() (int, bool), n int) func() (int, bool) { 
    return func() (int, bool) { 
     if n > 0 { 
      n -= 1 
      return stream() 
     } 
     return 0, false 
    } 
} 

func main() { 

    primes := take(sieve(gen_number_stream()), 50) 

    for i, ok := primes(); ok; i, ok = primes() { 
     fmt.Println(i) 
    } 

} 

當我運行這段代碼,它變得越來越慢,最後得到一個運行時錯誤是這樣的:

runtime: out of memory: [...] 

這裏是Python代碼的一個版本,它運行良好:

def gen_numbers(): 
    i = 2 
    while True: 
     yield i 
     i += 1 

def sieve(stream): 
    p = stream.next() 
    yield p 
    for i in sieve(i for i in stream if i % p != 0): 
     yield i 

def take(stream,n): 
    for i,s in enumerate(stream): 
     if i == 50: break 
     yield s 

def main(): 
    for i in take(sieve(gen_numbers()),50): 
     print i 


if __name__ == '__main__': 
    main() 

我想知道爲什麼以及如何解決它。這是我的代碼或golang編譯器的問題嗎? 謝謝!附:

PS:對不起,我的英文很差。

回答

1

我們重用流

if p, ok := stream(); ok { 
     remaining := filter_stream(stream, func(q int) bool { return q % p != 0 }) 

但對於每一個新的「p」你必須創建一個新的「stream2

if p, ok := stream(); ok { 
     stream2 := .... 
     remaining := filter_stream(stream2, func(q int) bool { return q % p != 0 }) 
+0

您能否爲stream2完成'....'? – VonC

+0

http://play.golang.org/p/in9euT48_Z – Max

+0

仍然不明白。我試過http://play.golang.org/p/LDtWC36c9V,但它不能正常工作 – VonC

2

的問題是你的篩函數是遞歸的。我懷疑你是通過循環不斷地遞歸調用篩來吹你的堆棧。

func sieve(stream func() (int, bool)) func() (int, bool) { 
    return func() (int, bool) { 
     if p, ok := stream(); ok { 
      remaining := filter_stream(stream, func(q int) bool { return q % p != 0 }) 
      stream = sieve(remaining) // just keeps calling sieve recursively which eventually blows your stack. 
      return p, true 
     } 
     return 0, false 
    } 
}