2016-05-13 14 views
9

Aşağıdaki kodlarım var. 1000000 argümanı ile çalıştırmak için 1s maliyeti, ancak myEven standart even işleviyle değiştirilecekse 5s maliyeti. Kodu kontrol ettim, standart bile fonksiyonu * myEven * ile aynı işlevi görür.Haskell'in 'bile' işlevi neden programımı yavaşlatıyor?

import Data.Word 
import Data.List 
import System.Environment 

collatzNext :: Word32 -> Word32 
collatzNext a = (if myEven a then a else 3*a+1) `div` 2 

myEven :: (Integral a) => a -> Bool 
myEven a = (a `rem` 2) == 0 

collatzLen :: Word32 -> Int 
collatzLen a0 = length $ takeWhile (/= 1) $ iterate collatzNext a0 

main = do 
    [a0] <- getArgs 
    let max_a0 = (read a0)::Word32 
    print $ maximum $ map (\a0 -> (collatzLen a0, a0)) [1..max_a0] 
+2

sadece emin olmak için - [info-page] 'i (https://stackoverflow.com/tags/haskell/info) okuyun ve programı -O2' seçeneği ile derlediniz mi? – epsilonhalbe

+2

@epsilonhalbe: Bu 7.10'da bir derleyici (iyi, kütüphane) regresyonu. Bununla birlikte, 8.0'de düzeltildi: https://ghc.haskell.org/trac/ghc/ticket/11701 – Zeta

cevap

12

{-# NOINLINE myEven #-} eklerseniz, aynı yavaşlamaya sahip olursunuz. Sorun, yerel olarak myEven'un tanımlanmış olmasıdır, bu nedenle kaynak derleyici için kullanılabilir ve satır içi olarak belirtilmiştir. Tüm tahsisleri ve fonksiyon çağrısı kendisi ortadan kaldırılmıştır:

Main.$wgo1 [InlPrag=[0], Occ=LoopBreaker] 
    :: GHC.Prim.Word# -> GHC.Prim.Int# -> GHC.Prim.Int# 
[GblId, Arity=2, Caf=NoCafRefs, Str=DmdType <S,1*U><L,U>] 
Main.$wgo1 = 
    \ (ww_s6n0 :: GHC.Prim.Word#) (ww1_s6n4 :: GHC.Prim.Int#) -> 
    case ww_s6n0 of wild_X2j { 
     __DEFAULT -> 
     case GHC.Prim.remWord# wild_X2j (__word 2) of _ [Occ=Dead] { 
      __DEFAULT -> 
      Main.$wgo1 
       (GHC.Prim.quotWord# 
       (GHC.Prim.narrow32Word# 
        (GHC.Prim.plusWord# 
         (GHC.Prim.narrow32Word# (GHC.Prim.timesWord# (__word 3) wild_X2j)) 
         (__word 1))) 
       (__word 2)) 
       (GHC.Prim.+# ww1_s6n4 1); 
      __word 0 -> 
      Main.$wgo1 
       (GHC.Prim.quotWord# wild_X2j (__word 2)) (GHC.Prim.+# ww1_s6n4 1) 
     }; 
     __word 1 -> ww1_s6n4 
    } 

Ama even diğer modülünde tanımlanan ve INLINE veya INLINEABLE olarak işaretlenmemiş. Sonuç olarak o inlined değildir ve even her çağrı Word32 kutulu ayırır:

Main.$wgo1 [InlPrag=[0], Occ=LoopBreaker] 
    :: GHC.Prim.Word# -> GHC.Prim.Int# -> GHC.Prim.Int# 
[GblId, Arity=2, Str=DmdType <S,U><L,U>] 
Main.$wgo1 = 
    \ (ww_s6mz :: GHC.Prim.Word#) (ww1_s6mD :: GHC.Prim.Int#) -> 
    case ww_s6mz of wild_X1W { 
     __DEFAULT -> 
     case even 
       @ Word32 GHC.Word.$fIntegralWord32 (GHC.Word.W32# wild_X1W) 
     of _ [Occ=Dead] { 
      False -> 
      Main.$wgo1 
       (GHC.Prim.quotWord# 
       (GHC.Prim.narrow32Word# 
        (GHC.Prim.plusWord# 
         (GHC.Prim.narrow32Word# (GHC.Prim.timesWord# (__word 3) wild_X1W)) 
         (__word 1))) 
       (__word 2)) 
       (GHC.Prim.+# ww1_s6mD 1); 
      True -> 
      Main.$wgo1 
       (GHC.Prim.quotWord# wild_X1W (__word 2)) (GHC.Prim.+# ww1_s6mD 1) 
     }; 
     __word 1 -> ww1_s6mD 
    } 

Not Int kullanırsanız sorun meydana geliyorsa bu yüzden Word32 için evenInt ve Integer için is specialized değil, o.

+5

Yup. Bunun [8.0] olarak düzeltileceğini unutmayın (https://ghc.haskell.org/trac/ghc/ticket/11701). – Zeta

+0

@Yuras: Teşekkürler. Int olarak değiştirildiyse, çalışma süresi 5 saniyeden 1.8 saniyeye düşürüldü. –