Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
为什么这个Haskell程序在使用优化编译时会泄漏空间?_Haskell_Optimization_Memory Leaks_Ghc - Fatal编程技术网

为什么这个Haskell程序在使用优化编译时会泄漏空间?

为什么这个Haskell程序在使用优化编译时会泄漏空间?,haskell,optimization,memory-leaks,ghc,Haskell,Optimization,Memory Leaks,Ghc,考虑下面的玩具程序,它计算一个字中所有字符替换的组合,这是密码中经常使用的类型 import Data.Char (isLower, toUpper) variants :: String -> [String] variants "" = [""] variants (c:s) = [c':s' | c' <- subst c, s' <- variants s] where subst 'a' = "aA@" subst 'e' = "eE3"

考虑下面的玩具程序,它计算一个字中所有字符替换的组合,这是密码中经常使用的类型

import Data.Char (isLower, toUpper)

variants :: String -> [String]
variants "" = [""]
variants (c:s) = [c':s' | c' <- subst c, s' <- variants s]
  where subst 'a' = "aA@"
        subst 'e' = "eE3"
        subst 'i' = "iI1"
        subst 'l' = "lL1"
        subst 'o' = "oO0"
        subst 's' = "sS$5"
        subst 'z' = "zZ2"
        subst x | isLower x = [x, toUpper x]
        subst x = [x]

main :: IO ()
main = putStrLn $ show $ length $ variants "redistributables"
现在
test0
test1
产生相同的输出,但是
test1
使用了更多的内存,并将大部分时间用于垃圾收集:

$ ./test0 +RTS -s 2>&1 | grep total
               2 MB total memory in use (0 MB lost due to fragmentation)
  Productivity  93.2% of total user, 93.3% of total elapsed

$ ./test1 +RTS -s 2>&1 | grep total
             188 MB total memory in use (0 MB lost due to fragmentation)
  Productivity  15.0% of total user, 15.0% of total elapsed
为什么?


我使用的是GHC 7.4.1;我可能应该使用一个更新的编译器,但这是我目前手头上的东西,不管怎样,问题可能出在我身上。

诀窍是导致后缀重新计算,而不是保留在内存中。这就像是和

powerset (x:xs) = map (x:) (powerset xs) ++ powerset xs 
定义,其中添加
where
子句是有害的(或者它是
powerset(x:xs)=powerset xs++map(x:)(powerset xs)
…)

在您的情况下,要尝试的代码是
mapM subst
,或者

variants (c:cs) = variants cs >>= \s-> map (:s) (subst c) 
从列表理解代码中可以看出,后一种方法的工作方向与“相反”,因此

variants (c:s) = [c':s' | s' <- variants s, c' <- subst c]
variants(c:s)=[c':s'| s'您想要的

variants (c:s) = [c':s' | c' <- subst c, s' <- variants s]

变体(c:s)=[c':s'| c'7.4在这一点上非常古老,如果不是7.10,至少使用7.8。要回答这个问题,您可能需要通过
-ddump siml
来获得核心输出,然后通过它来准确地找出区别。@bheklir这样做了。当然,生成的核心非常不同,但对于Ha来说确实很难skell新手需要解开,到目前为止,我还没有成功。@WillNess
-fn完全的懒惰没有什么区别。@WillNess前者会做,后者不会。诀窍是导致后缀重新计算,而不是保留在内存中。这就像
powerset(x:xs)=map(x:)(powerset xs)++powerset xs
定义,在其中添加
子句是有害的。(或者它是
powerset(x:xs)=powerset xs++map(x:)(powerset xs)
?)实际上,交换
c'
variants (c:s) = [c':s' | c' <- subst c, s' <- variants s]