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