我想学习使用ST-Monad。因此,我想为每个整数重写一些代码计算 - 达到极限 - 所有正确除数的列表。结果应该是一个数组,索引'n'的条目应该是它的正确除数列表。
通过为每个整数'n'计算其倍数的列表'l'并在索引'm'处为'l'的每个多个'm'添加到列表中的除数'n'来完成。
以下是我要修改的代码:
properDivisorsOf' :: forall a. (Integral a, Ix a) => a -> Array a [a]
properDivisorsOf' limit =
let generate :: (Integral a, Ix a) => a -> Array a [a] -> Array a [a]
generate n acc
| n > (limit `div` 2) = acc
| otherwise =
let acc' = acc // [(i, n : (acc ! i)) | i <- [2*n, 3*n .. limit]]
in generate (n + 1) acc'
in generate 1 (array (1, limit) [(i, [])| i <- [1..limit]])
这就是我尝试的方式:
properDivisorsOf :: forall a. (Integral a, Ix a) => a -> Array a [a]
properDivisorsOf limit =
let result :: ST s (STArray s a [a])
result = newArray (1, limit) [] -- In the beginning for every number: no divisors known (empty list)
update (index, divisor) = do
l <- readArray result index -- extracting list of divisors of number 'index'
let u = divisor : l
writeArray result index u -- and adding 'divisor' to the list
content :: [(a, a)]
content = do
n <- [1 .. (limit `div` 2)]
multiple <- [2*n, 3*n .. limit]
return (multiple, n)
doUpdate = map update content -- update result for all multiples (in content)
在runSTArray结果中
不幸的是它没有编译,错误信息对我没有任何意义。我有两个问题:
编辑:编译器消息
Couldn't match expected type `[t0]'
with actual type `STArray i0 a [a]'
In the second argument of `(:)', namely `l'
In the expression: divisor : l
In an equation for `u': u = divisor : l
失败,模块加载:无。
答案 0 :(得分:5)
2。经验丰富的Haskell-Programm如何在他必须使用ST-Monad(为了提高效率)的限制下解决这个问题?
我绝不是一位经验丰富的Haskell程序员,但我会使用代码下面的命令式代码,但这是从您的代码直接转换:
properDivisorsOf :: forall a. (Integral a, Ix a) => a -> Array a [a]
properDivisorsOf limit =
runSTArray $ do
result <- newArray (1, limit) []
mapM_ (update result) content
return result
where
content :: [(a, a)]
content = do
n <- [1 .. (limit `div` 2)]
multiple <- [2*n, 3*n .. limit]
return (multiple, n)
update arr (index, divisor) = do
l <- readArray arr index -- extracting list of divisors of number 'index'
let u = divisor : l
writeArray arr index u -- and adding 'divisor' to the list
您原来的功能:
main = print $ properDivisorsOf' 100000
$ .\Original.exe +RTS -s Original.exe: out of memory
我们通过100000
交换10000
:
221,476,488 bytes allocated in the heap 21,566,328 bytes copied during GC 172,813,068 bytes maximum residency (9 sample(s)) 4,434,480 bytes maximum slop 210 MB total memory in use (5 MB lost due to fragmentation) Tot time (elapsed) Avg pause Max pause Gen 0 378 colls, 0 par 0.41s 0.43s 0.0011s 0.0024s Gen 1 9 colls, 0 par 0.36s 0.37s 0.0409s 0.1723s INIT time 0.00s ( 0.00s elapsed) MUT time 0.28s ( 0.60s elapsed) GC time 0.77s ( 0.80s elapsed) EXIT time 0.00s ( 0.02s elapsed) Total time 1.05s ( 1.42s elapsed) %GC time 73.1% (56.4% elapsed) Alloc rate 787,471,957 bytes per MUT second Productivity 26.9% of total user, 19.8% of total elapsed
尽管程序速度非常快(毕竟只有1秒),210MB的内存占用量非常明显。此外,内存需要增加squre,限制为20000,你需要大约800 MB,20000大约1.9GB。
$ .\ST.exe +RTS -s > $null 300,728,400 bytes allocated in the heap 89,696,288 bytes copied during GC 13,628,272 bytes maximum residency (10 sample(s)) 292,972 bytes maximum slop 38 MB total memory in use (0 MB lost due to fragmentation) Tot time (elapsed) Avg pause Max pause Gen 0 565 colls, 0 par 0.14s 0.14s 0.0002s 0.0008s Gen 1 10 colls, 0 par 0.09s 0.08s 0.0076s 0.0223s INIT time 0.00s ( 0.00s elapsed) MUT time 0.11s ( 0.16s elapsed) GC time 0.23s ( 0.21s elapsed) EXIT time 0.00s ( 0.00s elapsed) Total time 0.34s ( 0.38s elapsed) %GC time 68.2% (56.6% elapsed) Alloc rate 2,749,516,800 bytes per MUT second Productivity 31.8% of total user, 28.9% of total elapsed
仅38 MB,这是原始实现的约17%,但计算的值是10倍(10000 vs 100000)。
如果你扔掉content
,你最终会得到以下程序:
import Data.Array (Array(..), Ix)
import Data.Array.ST (newArray, readArray, writeArray, runSTArray)
import Control.Monad (forM_)
properDivisorsOf :: (Integral a, Ix a) => a -> Array a [a]
properDivisorsOf limit =
runSTArray $ do
result <- newArray (1, limit) []
forM_ [1.. (limit `div`2)] $ \n -> do
forM_ [2*n, 3*n .. limit] $ \index -> do
l <- readArray result index
writeArray result index (n:l)
return result
main = print $ properDivisorsOf 100000
$ .\Imperative.exe +RTS -s > $null 237,323,392 bytes allocated in the heap 63,304,856 bytes copied during GC 13,628,276 bytes maximum residency (7 sample(s)) 138,636 bytes maximum slop 34 MB total memory in use (0 MB lost due to fragmentation) Tot time (elapsed) Avg pause Max pause Gen 0 447 colls, 0 par 0.12s 0.09s 0.0002s 0.0008s Gen 1 7 colls, 0 par 0.05s 0.06s 0.0087s 0.0224s INIT time 0.00s ( 0.00s elapsed) MUT time 0.11s ( 0.18s elapsed) GC time 0.17s ( 0.16s elapsed) EXIT time 0.00s ( 0.00s elapsed) Total time 0.30s ( 0.34s elapsed) %GC time 57.9% (45.9% elapsed) Alloc rate 2,169,813,869 bytes per MUT second Productivity 42.1% of total user, 36.9% of total elapsed
- 为什么不编译?如何正确提取条目?
醇>
我感觉,你正确提取(见上文,你使用的代码几乎相同),但update
的推断类型是错误的,因为你的用法并不正确。例如,update
应该在ST
monad中使用,因此您可以将其与mapM
一起使用,而不是map
。此外,还有其他一些问题,例如您定义doUpdate
但从不使用它。