2

我在Haskell寫了一個簡單的(情節較輕)素數生成器,具有相互遞歸定義,生成素數和確定數量的primeness:基於類型的具體性重構懶惰列表?

primes :: (Integral a) => [a] 
primes = 2 : filter isPrime [3, 5..] 

isPrime :: (Integral a) => a -> Bool 
isPrime m = all (indiv m) (takeWhile (<= (intSqrt m)) primes) 

intSqrt :: (Integral a) => a -> a 
intSqrt 1 = 1 
intSqrt n = div (m + (div (n - 1) m)) 2 
    where m = intSqrt (n - 1) 

indiv :: (Integral a) => a -> a -> Bool 
indiv m n = rem m n /= 0 

我注意到這是重建子列表已經產生的每參考撇到primes

*Main> take 200 primes 
[2,3,5,7, ..., 1223] 
(2.70 secs, 446142856 bytes) 
*Main> take 200 primes 
[2,3,5,7, ..., 1223] 
(2.49 secs, 445803544 bytes) 

但是,當我改變類型註釋用一個具體的整數類型,如

primes :: [Integer] 
isPrime :: Integer -> Bool 

每一個素只生成一次:

*Main> :r 
[1 of 1] Compiling Main    (Primes.hs, interpreted) 
Ok, modules loaded: Main. 
*Main> take 200 primes 
[2,3,5,7, ..., 1223] 
(2.15 secs, 378377848 bytes) 
*Main> take 200 primes 
[2,3,5,7, ..., 1223] 
(0.01 secs, 1626984 bytes) 

似乎很想我。這有什麼特別的原因?

回答

7

當你說

primes :: [Integer] 

然後primes是恆定的,但是當你說

primes :: (Integral a) => [a] 

那麼它是一個隱藏的參數功能:Integral實例取其型a是。和其他函數一樣,當你用相同的參數調用它時,它會重新計算它的結果(除非你明確地記住了它)。

+8

這種令人驚訝的缺乏共享,與「多態常量」發生時計算是[單態限制]引入(http://www.haskell.org/haskellwiki/Monomorphism_restriction)的原因。 – 2013-02-15 21:31:40

+1

啊,謝謝。回想起來這很有道理(雖然我不確定爲什麼它不能專門化,因此需要記憶)。 – 2013-02-15 22:13:22

+2

@JamesCunningham GHC識別[SPECIALIZED(http://www.haskell.org/ghc/docs/latest/html/users_guide/pragmas.html#specialize-pragma)編譯(雖然我沒有用它自己)。 – dave4420 2013-02-15 22:18:01