這裏是全新的Haskell程序員。剛剛完成「瞭解你一個Haskell」...我對一個有多少特定屬性的集合感興趣。我有一些小的參數值的工作代碼,但我想知道如何處理更大的結構。我知道Haskell可以做「無限的數據結構」,但我只是沒有看到如何從那裏走到那裏,並學習你一個Haskell /谷歌並沒有讓我這樣做。查找對內存來說太大的列表的大小?
下面是我的eSet
給「小」參數的工作代碼r
和t
import Control.Monad
import System.Environment
import System.Exit
myPred :: [Int] -> Bool
myPred a = myPred' [] a
where
myPred' [] [] = False
myPred' [] [0] = True
myPred' _ [] = True
myPred' acc (0:aTail) = myPred' acc aTail
myPred' acc (a:aTail)
| a `elem` acc = False
| otherwise = myPred' (a:acc) aTail
superSet :: Int -> Int -> [[Int]]
superSet r t = replicateM r [0..t]
eSet :: Int -> Int -> [[Int]]
eSet r t = filter myPred $ superSet r t
main :: IO()
main = do
args <- getArgs
case args of
[rArg, tArg] ->
print $ length $ eSet (read rArg) (read tArg)
[rArg, tArg, "set"] ->
print $ eSet (read rArg) (read tArg)
_ ->
die "Usage: eSet r r set <set optional for printing set itself otherwise just print the size
當編譯/運行,我得到
$ ghc eSet.hs -rtsopts
[1 of 1] Compiling Main (eSet.hs, eSet.o)
Linking eSet ...
$ # Here's is a tiny eSet to illustrate. It is the set of lists of r integers from zero to t with no repeated nonzero list entries
$ ./eSet 4 2 set
[[0,0,0,0],[0,0,0,1],[0,0,0,2],[0,0,1,0],[0,0,1,2],[0,0,2,0],[0,0,2,1],[0,1,0,0],[0,1,0,2],[0,1,2,0],[0,2,0,0],[0,2,0,1],[0,2,1,0],[1,0,0,0],[1,0,0,2],[1,0,2,0],[1,2,0,0],[2,0,0,0],[2,0,0,1],[2,0,1,0],[2,1,0,0]]
$ ./eSet 8 4 +RTS -sstderr
3393
174,406,136 bytes allocated in the heap
29,061,152 bytes copied during GC
4,382,568 bytes maximum residency (7 sample(s))
148,664 bytes maximum slop
14 MB total memory in use (0 MB lost due to fragmentation)
Tot time (elapsed) Avg pause Max pause
Gen 0 328 colls, 0 par 0.047s 0.047s 0.0001s 0.0009s
Gen 1 7 colls, 0 par 0.055s 0.055s 0.0079s 0.0147s
INIT time 0.000s ( 0.000s elapsed)
MUT time 0.298s ( 0.301s elapsed)
GC time 0.102s ( 0.102s elapsed)
EXIT time 0.001s ( 0.001s elapsed)
Total time 0.406s ( 0.405s elapsed)
%GC time 25.1% (25.2% elapsed)
Alloc rate 585,308,888 bytes per MUT second
Productivity 74.8% of total user, 75.0% of total elapsed
$ ./eSet 10 5 +RTS -sstderr
63591
27,478,010,744 bytes allocated in the heap
4,638,903,384 bytes copied during GC
532,163,096 bytes maximum residency (15 sample(s))
16,500,072 bytes maximum slop
1556 MB total memory in use (0 MB lost due to fragmentation)
Tot time (elapsed) Avg pause Max pause
Gen 0 52656 colls, 0 par 6.865s 6.864s 0.0001s 0.0055s
Gen 1 15 colls, 0 par 8.853s 8.997s 0.5998s 1.8617s
INIT time 0.000s ( 0.000s elapsed)
MUT time 52.652s (52.796s elapsed)
GC time 15.717s (15.861s elapsed)
EXIT time 0.193s ( 0.211s elapsed)
Total time 68.564s (68.868s elapsed)
%GC time 22.9% (23.0% elapsed)
Alloc rate 521,883,277 bytes per MUT second
Productivity 77.1% of total user, 76.7% of total elapsed
我看到我的內存使用率是非常高的,有一個很多垃圾收集。運行時eSet 12 6
我得到一個分段錯誤。
我覺得filter myPred $ superSet r t
讓我不再懶惰地讓子集一次一部分,所以我可以處理更大(但有限)的集合,但我不知道如何改變爲另一種方法來做到這一點。我認爲這是我的問題的根源。另外,因爲這是我的第一個Haskell程序,所以關於樣式以及如何實現「pythonic」的Haskell模擬的非常感謝!
也許在這裏並不重要,但在測量任何性能之前,請記住使用'-O2'或類似的東西開啓優化編譯。有時它會產生巨大的差異。 – chi
如果你只關心有多少,那麼一點組合應該讓你想要更便宜。如果聽起來很有意思,我很樂意再寫一個關於這個問題的答案。 –
@DanielWagner有點組合是最受歡迎的,也是一個很好的方法來幫助確認程序的正確性!請寫下來。 –