【问题标题】:Performance in pattern matching模式匹配的性能
【发布时间】:2016-10-28 13:33:09
【问题描述】:

我正在阅读Learn you a Haskell,特别是关于模式匹配的章节。以下是本教程中用于计算列表长度的代码:

length' :: (Num b) => [a] -> b  
length' [] = 0  
length' (_:xs) = 1 + length' xs

我的问题是,反转递归顺序(通过将基本情况放在下面)会显示任何显着的性能提升吗?

length' :: (Num b) => [a] -> b
length' (_:xs) = 1 + length' xs
length' [] = 0

【问题讨论】:

    标签: performance haskell pattern-matching


    【解决方案1】:

    不,这不会提供任何性能提升。在这两种情况下,编译器都必须评估其 WHNF 的参数以检查它是否为空列表。

    实际上,这个函数很可能会在编译期间被重写,生成的代码与您编写的完全不同(假设您使用优化进行编译)。

    查看生成的核心(编译后没有优化):

    (letrec {
       f1_aLn [Occ=LoopBreaker] :: [Integer] -> Integer
       [LclId, Arity=1, Str=DmdType]
       f1_aLn =
         \ (ds_d1gX :: [Integer]) ->
           case ds_d1gX of _ [Occ=Dead] {
             [] -> fromInteger @ Integer GHC.Num.$fNumInteger 0;
             : ds1_d1h4 xs_at0 ->
               + @ Integer
                 GHC.Num.$fNumInteger
                 (fromInteger @ Integer GHC.Num.$fNumInteger 1)
                 (f1_aLn xs_at0)
           }; } in
    f1_aLn (enumFromTo @ Integer GHC.Enum.$fEnumInteger 1 100))
    
    (letrec {
       f2_aBk [Occ=LoopBreaker] :: [Integer] -> Integer
       [LclId, Arity=1, Str=DmdType]
       f2_aBk =
         \ (ds_d1gP :: [Integer]) ->
           case ds_d1gP of _ [Occ=Dead] {
             [] -> fromInteger @ Integer GHC.Num.$fNumInteger 0;
             : ds1_d1gW xs_aBh ->
               + @ Integer
                 GHC.Num.$fNumInteger
                 (fromInteger @ Integer GHC.Num.$fNumInteger 1)
                 (f2_aBk xs_aBh)
           }; } in
    f2_aBk (enumFromTo @ Integer GHC.Enum.$fEnumInteger 1 100))
    

    我们可以看到编译器生成了等价的语句。仅供参考,这是代码:

    main = do
             print $ f1 [1..100]
             print $ f2 [1..100]
    
    f1 [] = 0
    f1 (_:xs) = 1 + f1 xs
    f2 (_:xs) = 1 + f2 xs
    f2 [] = 0
    

    ghc -ddump-simpl file.hs编译

    【讨论】:

    【解决方案2】:

    只有两种情况,顺序并不重要。对于三个的情况,顺序不会影响性能,但可以简化代码。例如,假设您有一个函数对空列表或单例列表执行大致相同的操作,但在具有 2 个或更多项目的列表上递归。您可以编写从最简单到最复杂的模式:

    foo [] = []
    foo [x] = [x]
    foo (x:y:rest) = x+y : foo (y:rest)
    

    或者,您可以通过先处理更复杂的情况将其减少到两种情况:

    foo (x:y:rest) = x+y : foo (y:rest)
    foo short = short
    

    因为foo = id 用于两个短案例。

    【讨论】:

      猜你喜欢
      • 2011-06-13
      • 2023-03-12
      • 1970-01-01
      • 2016-05-16
      • 2019-06-17
      • 1970-01-01
      • 2011-05-10
      • 2015-09-04
      • 1970-01-01
      相关资源
      最近更新 更多