Rozważmy następujący program zabawkowy, który wylicza wszystkie kombinacje zastąpień znaków w słowie, rodzaju często używanego w hasłach.Dlaczego ten program Haskell traci przestrzeń po kompilacji z optymalizacją?
import Data.Char (isLower, toUpper)
variants :: String -> [String]
variants "" = [""]
variants (c:s) = [c':s' | c' <- subst c, s' <- variants s]
where subst 'a' = "[email protected]"
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"
skompilować go i bez optymalizacji:
$ ghc -fforce-recomp -Wall Test.hs -o test0
[1 of 1] Compiling Main (Test.hs, Test.o)
Linking test0 ...
$ ghc -fforce-recomp -O -Wall Test.hs -o test1
[1 of 1] Compiling Main (Test.hs, Test.o)
Linking test1 ...
Teraz test0
i test1
wytwarzają taką samą moc, ale test1
korzysta znacznie więcej pamięci i spędza większość czasu w zbieranie śmieci:
$ ./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
Dlaczego?
Używam GHC 7.4.1; Prawdopodobnie powinienem użyć nowszego kompilatora, ale to jest właśnie to, co mam w tej chwili pod ręką, a wina prawdopodobnie i tak leży u mnie.
7.4 jest dość stara w tym miejscu, przynajmniej użyj 7.8, jeśli nie 7.10. Aby odpowiedzieć na to pytanie, prawdopodobnie będziesz musiał przekazać '-ddump-simpl', aby uzyskać podstawowe wyjście, a następnie przejść przez to, aby dowiedzieć się, jaka jest różnica. – bheklilr
@bheklilr Zrobione. Oczywiście wygenerowany Rdzeń jest bardzo różny, ale dla początkującego Haskella naprawdę trudno jest rozwikłać i jak dotąd nie udało mi się. –
i co dzieje się z flagą -O2? –