关于haskell的严格性

时间:2014-05-23 17:37:20

标签: haskell thunk strictness

我创建了以下Haskell prime函数(在ghci中):

let pi :: Int -> Int -> Int;
pi 1 _ = 2;
pi x y = if all (/=0) (map (rem y) [pi z 2| z <- [1..(x-1)]]) then y else pi x (y+1);

请不要介意第二个/ memoized参数(它应始终从2开始)。 当然,正如预期的那样,thunk很快失去控制。需要超过19秒确认43是第14个素数...

Prelude> pi 10 2
29
(0.14 secs, 23924220 bytes)
Prelude> pi 11 2
31
(0.48 secs, 71394644 bytes)
Prelude> pi 12 2
37
(1.64 secs, 244218772 bytes)
Prelude> pi 13 2
41
(5.57 secs, 832500204 bytes)
Prelude> pi 14 2
43
(19.11 secs, 2841677968 bytes)

我已经阅读了严格性(主要是seq$!),但我的所有尝试都花了更长时间!

2 个答案:

答案 0 :(得分:3)

如果您在功能中添加trace以查看评估了对pi的哪些来电,那么您会发现您的实施并未使用已计算的值。

import Prelude hiding (pi)
import Debug.Trace (trace)

pi :: Int -> Int -> Int
pi 1 y = trace ("pi 1 " ++ show y) 2
pi x y =
    trace ("pi " ++ show x ++ " " ++ show y) $
    if all (/=0) (map (rem y) [pi z 2| z <- [1..(x-1)]])
        then y
        else pi x (y+1)

评估pi 3 2现在打印以下内容(我添加了空格,以显示结构类型):

pi 3 2
    pi 1 2
pi 3 3
    pi 1 2
    pi 2 2
        pi 1 2
    pi 2 3
        pi 1 2
pi 3 4
    pi 1 2
pi 3 5
    pi 1 2
    pi 2 2
        pi 1 2
    pi 2 3
        pi 1 2

您会看到很多冗余,对于x的较高值,这会出现指数级的恶化。懒惰在这里不是你的问题,你不会传播到目前为止你计算的价值。换句话说,问题在于您的方法,而且现在很难修复它。

答案 1 :(得分:0)

pi = (!!) primes . subtract 1

primes = 2 : filter isPrime [3..]

isPrime n = all ((/=) 0 . rem n)) $ takeWhile ((>=) n . (^2)) primes

> pi 14
43
it :: Integer
(0.00 secs, 0 bytes)