我认为Cont
monad只相当于CPS Transformation,所以如果我有
一个monadic sum,如果我在Identity
monad中运行,它将因堆栈溢出而失败,如果
我在Cont
Monad中运行它,由于尾递归会没问题。
所以我写了一个简单的程序来验证我的想法。但令我惊讶的是,由于我的知识有限,结果是不合理的。
所有程序均使用ghc --make Test.hs -o test && ./test
sum0 n = if n==0 then 0 else n + sum0 (n-1)
sum1 n = if n==0 then return 0 else sum1 (n-1) >>= \ v -> seq v (return (n+v))
sum2 n k = if n == 0 then k 0 else sum2 n (\v -> k (n + v))
sum3 n k = if n == 0 then k 0 else sum3 n (\ !v -> k (n + v))
sum4 n k = if n == 0 then k 0 else sum4 n (\ v -> seq v ( k (n + v)))
sum5 n = if n==0 then return 0 else sum5 (n-1) >>= \ v -> (return (n+v))
main = print (sum0 3000000)
堆栈溢出。这是合理的。
main = print (flip runCont id (sum1 3000000))
使用180M内存,这是合理的,但我不清楚为什么seq
需要这里,因为在n
变为0之前它的继续不适用。
main = print (flip runCont id (sum5 3000000))
堆栈溢出。为什么?
main = print (flip runCont (const 0) (sum1 3000000))
使用130M内存。这是合理的。
main = print (flip runCont (const 0) (sum5 3000000))
使用118M内存。这是合理的。
main = print (sum2 3000000 (const 0))
使用大量内存(超过1G)。我认为sum2
相当于sum5
(当sum5
位于Cont
monad时)。为什么呢?
main = print (sum3 3000000 (const 0))
使用大量内存。我认为sum3
相当于sum1
(Cont
monad)。为什么?
main = print (runIdentity (sum1 3000000))
堆栈溢出,正是我想要的。
main = print (sum3 3000000 id)
使用大量内存。相当于sum1
,为什么?
main = print (sum4 3000000 id)
使用大量内存。相当于sum1,为什么?
main = print (sum [1 .. 3000000])
堆栈溢出。 sum = foldl (+) 0
的来源,所以这是合理的。
main = print (foldl' (+) 0 [1 .. 3000000])
使用1.5M。
答案 0 :(得分:3)
首先,我认为sum2
,sum3
和sum4
从未真正减少n
。所以他们使用了大量的内存,因为他们正在进入一个无限循环来进行分配。
在纠正之后,我再次使用以下结果运行每个测试,其中“分配”指的是近似峰值内存使用:
main = print (sum0 3000000)
:在分配很少的内存后,堆栈溢出main = print (flip runCont id (sum1 3000000))
:成功,分配类似于您所看到的金额main = print (flip runCont id (sum5 3000000))
:在将类似的内存量分配为sum1
后,堆栈溢出。main = print (flip runCont (const 0) (sum1 3000000))
:成功,与上述类似的分配main = print (flip runCont (const 0) (sum5 3000000))
:相同main = print (sum2 3000000 (const 0))
:成功,约为sum1
main = print (sum3 3000000 (const 0))
:成功,约为sum1
main = print (runIdentity (sum1 3000000))
:堆栈溢出,分配很少main = print (sum3 3000000 id)
:成功,约为sum1
main = print (sum4 3000000 id)
:成功,约为sum1
main = print (sum [1 .. 3000000])
:堆栈溢出,分配约为sum1
main = print (foldl' (+) 0 [1 .. 3000000])
:成功,几乎没有分配这主要是您所期望的,除了seq
在sum1
与sum5
之间产生差异的原因除外。